[Crash-utility] kmem -s issue (gdb can't get offest of struct page lru member)

Dave Anderson anderson at redhat.com
Mon Jan 9 19:06:39 UTC 2012



----- Original Message -----
> Hello Dave,
> 
> When issuing "kmem -s" with crash 6.0.2 (same with 6.0.0) on a s390x
> linux-3.2 kernel dump, I get the following:
> 
> ...
> 1ff0a600         signal_cache            1104        112       150      6    32k
> 1ff0a540         sighand_cache           2088         82        98      7    32k
> 
> kmem: invalid structure member offset: page_lru
>       FILE: memory.c  LINE: 15856  FUNCTION: count_partial()
> 
> [./crash] error trace: 80099674 => 80097156 => 80083c40 => 801206ba
> 
>   801206ba: OFFSET_verify+138
>   80083c40: get_kmem_cache_slub_data+1028
>   80097156: dump_kmem_cache_slub+902
>   80099674: cmd_kmem+6636
> 
> kmem: invalid structure member offset: page_lru
>       FILE: memory.c  LINE: 15856  FUNCTION: count_partial()
> 
> 
> 
> I think the reason is that MEMBER_OFFSET_INIT(page_lru, "page", "lru") fails.
> See the following gdb session:
> 
> 
> Breakpoint 1, vm_init () at memory.c:375
> 375             MEMBER_OFFSET_INIT(page_lru, "page", "lru");
> (gdb) s
> datatype_info (name=0x80415c4a "page", member=0x803ce36c "lru",
> dm=0x0)
>     at symbols.c:4919
> 4919            if (dm == ANON_MEMBER_OFFSET_REQUEST)
> (gdb) n
> 4922            strcpy(buf, name);
> (gdb) n
> 4924            req = (struct gnu_request *)GETBUF(sizeof(struct
> gnu_request));
> (gdb) n
> 4925            req->command = GNU_GET_DATATYPE;
> (gdb) n
> 4926            req->flags |= GNU_RETURN_ON_ERROR;
> (gdb) n
> 4927            req->name = buf;
> (gdb) n
> 4928            req->member = member;
> (gdb) n
> 4929            req->fp = pc->nullfp;
> (gdb) n
> 4931            gdb_interface(req);
> (gdb) n
> 4932            if (req->flags & GNU_COMMAND_FAILED) {
> (gdb) print *req
> $1 = {command = 5, buf = 0x0, fp = 0x8060d540, addr = 0, addr2 = 0,
> count = 0,
>   flags = 8, name = 0x3ffffffda94 "page", length = 56, typecode = 3,
>   typename = 0x0, target_typename = 0x0, target_length = 0,
>   target_typecode = 0, is_typedef = 0, member = 0x803ce36c "lru",
>   member_offset = -1, member_length = 0, member_typecode = 0, value =
>   0,
>   tagname = 0x0, pc = 0, sp = 0, ra = 0, curframe = 0, frame = 0,
>   prevsp = 0,
>   prevpc = 0, lastsp = 0, task = 0, debug = 0, hookp = 0x0}
> 
> ---> member_offset = -1
> 
> (gdb) n
> 4937            if (!req->typecode) {
> (gdb) n
> 4942            if (!req->typecode) {
> (gdb) n
> 4947            member_typecode = TYPE_CODE_UNDEF;
> (gdb) n
> 4948            member_size = 0;
> (gdb) n
> 4949            type_found = 0;
> (gdb) n
> 4951            if (CRASHDEBUG(2)) {
> (gdb) n
> 4965            switch (req->typecode)
> (gdb) n
> 4968                    type_found = STRUCT_REQUEST;
> (gdb) n
> 4969                    size = req->length;
> (gdb) n
> 4970                    if (req->member_offset >= 0) {
> (gdb) n
> 4975                            offset = -1;
> (gdb) n
> 4976                            member_size = 0;
> 
> Also crash can't evaluate the offset of the "lru" member:
> 
> crash> struct page
> struct page {
>     long unsigned int flags;
>     struct address_space *mapping;
>     struct {
>         union {...};
>         union {...};
>     };
>     union {
>         struct list_head lru;
>         struct {...};
>     };
>     union {
>         long unsigned int private;
>         spinlock_t ptl;
>         struct kmem_cache *slab;
>         struct page *first_page;
>     };
> }
> SIZE: 56
> 
> crash> struct page.mapping
> struct page {
>    [8] struct address_space *mapping;
> }
> 
> crash> struct page.lru
> struct: invalid data structure reference: page.lru
> 
> Any idea why we do not get the offset from gdb?
> Perhaps a problem with the anonymous union?

Right -- it's due to commit 49e2258586b423684f03c278149ab46d8f8b6700,
which moved the page.lru field into an anonymous structure:

          /* Third double word block */
  -       struct list_head lru;           /* Pageout list, eg. active_list
  +       union {
  +               struct list_head lru;   /* Pageout list, eg. active_list
                                           * protected by zone->lru_lock !
                                           */
  +               struct {                /* slub per cpu partial pages */
  +                       struct page *next;      /* Next partial slab */
  +#ifdef CONFIG_64BIT
  +                       int pages;      /* Nr of partial slabs left */
  +                       int pobjects;   /* Approximate # of objects */
  +#else
  +                       short int pages;
  +                       short int pobjects;
  +#endif
  +               };
  +       };

And see https://www.redhat.com/archives/crash-utility/2012-January/msg00023.html
for the gdb-related details.
  
Can you try a patch like this to vm_init():

        MEMBER_OFFSET_INIT(page_lru, "page", "lru");
+	if (INVALID_MEMBER(page_lru))
+               ANON_MEMBER_OFFSET_INIT(page_lru, "page", "lru");

Thanks,
  Dave




More information about the Crash-utility mailing list