[Crash-utility] kmem: WARNING: cannot find mem_map page for address

Dave Anderson anderson at redhat.com
Tue Dec 18 22:12:09 UTC 2012



----- Original Message -----
> Hi Dave,
> 
> On Tue, Dec 18, 2012 at 6:52 AM, Dave Anderson <anderson at redhat.com>
> wrote:
> >  #define __page_to_pfn(pg)                                       \
> >  ({      const struct page *__pg = (pg);                         \
> >          int __sec = page_to_section(__pg);                      \
> >          (unsigned long)(__pg -
> >          __section_mem_map_addr(__nr_to_section(__sec))); \
> >  })
> >
> > Maybe you could play around with emulating that macro w/crash, and
> > see what comes up?
> 
> Hey, that was sure fun.  :(

It's a nightmare, isn't it?
 
> Since "struct page" is another name for "cfs_page_t":
> 
> > crash> p $tp->page->flags
> > $9 = 0x200000000000000
> 
> "page to section" is a 43 bit right shift:
> 
> > crash> p ($tp->page->flags >> 43)
> > $10 = 0x4000
> 
> > static inline struct mem_section *__nr_to_section(unsigned long nr)
> > {
> >         if (!mem_section[SECTION_NR_TO_ROOT(nr)])
> >                 return NULL;
> >         return &mem_section[SECTION_NR_TO_ROOT(nr)][nr &
> >         SECTION_ROOT_MASK];
> > }
> 
> There are 16 maps per mem section, so a 4 bit shift and mask yield:
> 
>    return &mem_section[0x400][0]
> 
> > crash> p mem_section[0x400]
> > $13 = (struct mem_section *) 0xffffffff81a26658
> > crash> p mem_section[0x400][0x0]
> > $14 = {
> >   section_mem_map = 0xffffffff81a26630,
> >   pageblock_flags = 0xffffffff81a26680
> > }
> 
> So the result of __page_to_pfn is the difference between
> > crash> p $pg
> > $24 = (cfs_page_t *) 0xffffea001bb1d1e8
> 
> and the return result of
>    __section_mem_map_addr((struct mem_section *) 0xffffffff81a26658)
> 
> > static inline struct page *__section_mem_map_addr(struct
> > mem_section *section)
> > {
> >         unsigned long map = section->section_mem_map;
> >         map &= SECTION_MAP_MASK;
> >         return (struct page *)map;
> > }
> 
> SECTION_MAP_MASK maps off the low order 3 bits, yielding:
>    (cfs_page_t *) 0xffffffff81a26630
> 
> > crash> gdb set $mpg = (cfs_page_t *)0xffffffff81a26630
> > crash> p ($pg - $mpg)
> > $32 = 0xffffff9b707721ed
> 
> Now what do I do with that number? :)  It is the difference between
> the numeric values of $pg and $mpg, divided by the size of "struct page"
> (which is 0x38 bytes) and sign extended.

The $mpg value would also have to resolve to a vmemmap address (ffffea00...),
which would have to be smaller in value than your $pg address of 0xffffea001bb1d1e8
in order for it to make sense.

So, you show that you stripped off 3 bits from something (not shown) in order
to get the $mpg of 0xffffffff81a26630 -- which should be derived from the
section_mem_map member of the mem_section at address 0xffffffff81a26658.   
What did the mem_section structure look like?  In other words:

 crash> struct mem_section 0xffffffff81a26658
 struct mem_section {
   section_mem_map =  <vmemmap-addr-you-need-to-strip-3-bits-from>
   ...

Here's an example mem_section:

 crash> struct mem_section ffff88021e5eb000 -x
 struct mem_section {
   section_mem_map = 0xffffea0000000003, 
   pageblock_flags = 0xffff88021e1eaa00, 
   page_cgroup = 0xffff880215880000, 
   pad = 0x0
 }

where the section_mem_map field contains a vmemmap address plus a few
flag bits in the lower byte.

Dave






More information about the Crash-utility mailing list