On Fri, Sep 20, 2024 at 9:30 AM <devel-request(a)lists.crash-utility.osci.io>
wrote:
 Date: Fri, 20 Sep 2024 01:28:32 -0000
 From: qiwu.chen(a)transsion.com
 Subject: [Crash-utility] [PATCH v3] kmem: fix the determination for
         slab page
 To: devel(a)lists.crash-utility.osci.io
 Message-ID: <20240920012832.29184.28326(a)lists.crash-utility.osci.io>
 Content-Type: text/plain; charset="utf-8"
 The determination for a slab page has changed due to changing
 PG_slab from a page flag to a page type since kernel commit
 46df8e73a4a3.
 Before apply this patch:
 crash> kmem -s ffff000002aa4100
 kmem: address is not allocated in slab subsystem: ffff000002aa4100
 After apply this patch:
 crash> kmem -s ffff000002aa4100
 CACHE             OBJSIZE  ALLOCATED     TOTAL  SLABS  SSIZE  NAME
 ffff00000140f900     4096         94       126     18    32k  task_struct
   SLAB              MEMORY            NODE  TOTAL  ALLOCATED  FREE
   fffffdffc00aa800  ffff000002aa0000     0      7          5     2
   FREE / [ALLOCATED]
   [ffff000002aa4100]
 Signed-off-by: qiwu.chen <qiwu.chen(a)transsion.com>
 ---
  defs.h    |  7 ++++++
  memory.c  | 68 ++++++++++++++++++++++++++++++++++++++++++++++---------
  symbols.c |  2 ++
  3 files changed, 66 insertions(+), 11 deletions(-)
 
Thank you for the update, qiwu.
I have no other issues, for the v3: Ack
Thanks
Lianbo
 diff --git a/defs.h b/defs.h
 index 2231cb6..e2a9278 100644
 --- a/defs.h
 +++ b/defs.h
 @@ -2243,6 +2243,7 @@ struct offset_table {                    /* stash of
 commonly-used offsets */
         long vmap_node_busy;
         long rb_list_head;
         long file_f_inode;
 +       long page_page_type;
  };
  struct size_table {         /* stash of commonly-used sizes */
 @@ -2651,6 +2652,7 @@ struct vm_table {                /* kernel
 VM-related data */
         ulong max_mem_section_nr;
         ulong zero_paddr;
         ulong huge_zero_paddr;
 +       uint page_type_base;
  };
  #define NODES                       (0x1)
 @@ -2684,6 +2686,11 @@ struct vm_table {                /* kernel
 VM-related data */
  #define SLAB_CPU_CACHE       (0x10000000)
  #define SLAB_ROOT_CACHES     (0x20000000)
  #define USE_VMAP_NODES       (0x40000000)
 +/*
 + * The SLAB_PAGEFLAGS flag is introduced to detect the change of
 + * PG_slab's type from a page flag to a page type.
 + */
 +#define SLAB_PAGEFLAGS       (0x80000000)
  #define IS_FLATMEM()           (vt->flags & FLATMEM)
  #define IS_DISCONTIGMEM()      (vt->flags & DISCONTIGMEM)
 diff --git a/memory.c b/memory.c
 index 967a9cf..8befe8c 100644
 --- a/memory.c
 +++ b/memory.c
 @@ -351,6 +351,43 @@ static ulong handle_each_vm_area(struct
 handle_each_vm_area_args *);
  static ulong DISPLAY_DEFAULT;
 +/*
 + * Before kernel commit ff202303c398e, the value is defined as a macro,
 so copy it here;
 + * After this commit, the value is defined as an enum, which can be
 evaluated at runtime.
 + */
 +#define PAGE_TYPE_BASE 0xf0000000
 +#define PageType(page_type, flag)
       \
 +       ((page_type & (vt->page_type_base | flag)) == vt->page_type_base)
 +
 +static void page_type_init(void)
 +{
 +       if (!enumerator_value("PAGE_TYPE_BASE", (long
 *)&vt->page_type_base))
 +               vt->page_type_base = PAGE_TYPE_BASE;
 +}
 +
 +/*
 + * The PG_slab's type has changed from a page flag to a page type
 + * since kernel commit 46df8e73a4a3.
 + */
 +static bool page_slab(ulong page, ulong flags)
 +{
 +       if (vt->flags & SLAB_PAGEFLAGS) {
 +               if ((flags >> vt->PG_slab) & 1)
 +                       return TRUE;
 +       }
 +
 +       if (VALID_MEMBER(page_page_type)) {
 +               uint page_type;
 +
 +               readmem(page+OFFSET(page_page_type), KVADDR, &page_type,
 +                       sizeof(page_type), "page_type", FAULT_ON_ERROR);
 +               if (PageType(page_type, (uint)vt->PG_slab))
 +                       return TRUE;
 +       }
 +
 +       return FALSE;
 +}
 +
  /*
   *  Verify that the sizeof the primitive types are reasonable.
   */
 @@ -504,6 +541,7 @@ vm_init(void)
                 ANON_MEMBER_OFFSET_INIT(page_compound_head, "page",
 "compound_head");
         MEMBER_OFFSET_INIT(page_private, "page", "private");
         MEMBER_OFFSET_INIT(page_freelist, "page", "freelist");
 +       MEMBER_OFFSET_INIT(page_page_type, "page", "page_type");
         MEMBER_OFFSET_INIT(mm_struct_pgd, "mm_struct", "pgd");
 @@ -1278,6 +1316,8 @@ vm_init(void)
         page_flags_init();
 +       page_type_init();
 +
         rss_page_types_init();
         vt->flags |= VM_INIT;
 @@ -5931,7 +5971,7 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
                                         if ((flags >> v22_PG_Slab) & 1)
                                                 slabs++;
                                 } else if (vt->PG_slab) {
 -                                       if ((flags >> vt->PG_slab) & 1)
 +                                       if (page_slab(pp, flags))
                                                 slabs++;
                                 } else {
                                         if ((flags >> v24_PG_slab) & 1)
 @@ -6381,7 +6421,7 @@ dump_mem_map(struct meminfo *mi)
                                         if ((flags >> v22_PG_Slab) & 1)
                                                 slabs++;
                                 } else if (vt->PG_slab) {
 -                                       if ((flags >> vt->PG_slab) & 1)
 +                                       if (page_slab(pp, flags))
                                                 slabs++;
                                 } else {
                                         if ((flags >> v24_PG_slab) & 1)
 @@ -6694,7 +6734,6 @@ dump_hstates()
         FREEBUF(hstate);
  }
 -
  static void
  page_flags_init(void)
  {
 @@ -6775,6 +6814,9 @@ page_flags_init_from_pageflag_names(void)
                 vt->pageflags_data[i].name = nameptr;
                 vt->pageflags_data[i].mask = mask;
 +                if (!strncmp(nameptr, "slab", 4))
 +                        vt->flags |= SLAB_PAGEFLAGS;
 +
                 if (CRASHDEBUG(1)) {
                         fprintf(fp, "  %08lx %s\n",
                                 vt->pageflags_data[i].mask,
 @@ -6835,8 +6877,9 @@ page_flags_init_from_pageflags_enum(void)
                         }
                         strcpy(nameptr, arglist[0] + strlen("PG_"));
                         vt->pageflags_data[p].name = nameptr;
 -                       vt->pageflags_data[p].mask = 1 <<
 atoi(arglist[2]);
 -
 +                       vt->pageflags_data[p].mask = 1 << atoi(arglist[2]);
 +                       if (!strncmp(nameptr, "slab", 4))
 +                               vt->flags |= SLAB_PAGEFLAGS;
                         p++;
                 }
         } else
 @@ -9736,14 +9779,14 @@ vaddr_to_kmem_cache(ulong vaddr, char *buf, int
 verbose)
                 readmem(page+OFFSET(page_flags), KVADDR,
                         &page_flags, sizeof(ulong), "page.flags",
                         FAULT_ON_ERROR);
 -               if (!(page_flags & (1 << vt->PG_slab))) {
 +               if (!page_slab(page, page_flags)) {
                         if (((vt->flags & KMALLOC_SLUB) ||
 VALID_MEMBER(page_compound_head)) ||
                             ((vt->flags & KMALLOC_COMMON) &&
                             VALID_MEMBER(page_slab) &&
 VALID_MEMBER(page_first_page))) {
 readmem(compound_head(page)+OFFSET(page_flags), KVADDR,
                                         &page_flags, sizeof(ulong),
 "page.flags",
                                         FAULT_ON_ERROR);
 -                               if (!(page_flags & (1 << vt->PG_slab)))
 +                               if (!page_slab(compound_head(page),
 page_flags))
                                         return NULL;
                         } else
                                 return NULL;
 @@ -14108,6 +14151,8 @@ dump_vm_table(int verbose)
                 fprintf(fp, "%sNODELISTS_IS_PTR", others++ ? "|" :
"");\
         if (vt->flags & VM_INIT)
                 fprintf(fp, "%sVM_INIT", others++ ? "|" :
"");\
 +       if (vt->flags & SLAB_PAGEFLAGS)
 +               fprintf(fp, "%sSLAB_PAGEFLAGS", others++ ? "|" :
"");\
         fprintf(fp, ")\n");
         if (vt->kernel_pgd[0] == vt->kernel_pgd[1])
 @@ -14237,6 +14282,7 @@ dump_vm_table(int verbose)
                         vt->pageflags_data[i].mask,
                         vt->pageflags_data[i].name);
         }
 +       fprintf(fp, "     page_type_base: %x\n", vt->page_type_base);
         dump_vma_cache(VERBOSE);
  }
 @@ -20195,7 +20241,7 @@ char *
  is_slab_page(struct meminfo *si, char *buf)
  {
         int i, cnt;
 -       ulong page_slab, page_flags, name;
 +       ulong pg_slab, page_flags, name;
          ulong *cache_list;
          char *retval;
 @@ -20210,11 +20256,11 @@ is_slab_page(struct meminfo *si, char *buf)
             RETURN_ON_ERROR|QUIET))
                 return NULL;
 -       if (!(page_flags & (1 << vt->PG_slab)))
 +       if (!page_slab(si->spec_addr, page_flags))
                 return NULL;
         if (!readmem(si->spec_addr + OFFSET(page_slab), KVADDR,
 -           &page_slab, sizeof(ulong), "page.slab",
 +           &pg_slab, sizeof(ulong), "page.slab",
             RETURN_ON_ERROR|QUIET))
                 return NULL;
 @@ -20222,7 +20268,7 @@ is_slab_page(struct meminfo *si, char *buf)
          cnt = get_kmem_cache_list(&cache_list);
         for (i = 0; i < cnt; i++) {
 -               if (page_slab == cache_list[i]) {
 +               if (pg_slab == cache_list[i]) {
                         if (!readmem(cache_list[i] +
 OFFSET(kmem_cache_name),
                             KVADDR, &name, sizeof(char *),
                             "kmem_cache.name", QUIET|RETURN_ON_ERROR))
 diff --git a/symbols.c b/symbols.c
 index 69a1fbb..014cd29 100644
 --- a/symbols.c
 +++ b/symbols.c
 @@ -10339,6 +10339,8 @@ dump_offset_table(char *spec, ulong makestruct)
          fprintf(fp, "            page_compound_head: %ld\n",
                  OFFSET(page_compound_head));
          fprintf(fp, "                  page_private: %ld\n",
 OFFSET(page_private));
 +       fprintf(fp, "                page_page_type: %ld\n",
 +               OFFSET(page_page_type));
         fprintf(fp, "        trace_print_flags_mask: %ld\n",
                 OFFSET(trace_print_flags_mask));
 --
 2.25.1