Can you show a before-and-after example of the "kmem -s" and "kmem -S"
output of a particular slab where your patch makes a difference?

Thanks,
  Dave

----- Original Message -----
> Hi,
> 
> SLUB cpu_slab has 2 freelist. One is cpu_slab->freelist for local
> cpu. One is cpu_slab->page->freelist for remote cpu.
> 
> So, we have to check both of freelists to know details.  Note,
> page->inuse counts only for free on page->freelist, not
> cpu_slab->freelist.
> 
> so total free objects are
> 
>       (page->objects - page->inuse) + count(cpu_slab->freelist))
> ---
> 
>  memory.c |  213
>  ++++++++++++++++++++++++++++----------------------------------
>  1 file changed, 99 insertions(+), 114 deletions(-)
> 
> diff -puN memory.c~crash-slub-freelist-fix memory.c
> --- crash-64/memory.c~crash-slub-freelist-fix 2016-04-18 02:29:57.743774055
> +0900
> +++ crash-64-hirofumi/memory.c        2016-04-18 02:32:30.999515870 +0900
> @@ -17914,15 +17914,62 @@ bailout:
>       FREEBUF(si->cache_buf);
>  }
>  
> +static ushort slub_page_objects(struct meminfo *si, ulong page)
> +{
> +     ulong objects_vaddr;
> +     ushort objects;
> +
> +     /*
> +      *  Pre-2.6.27, the object count and order were fixed in the
> +      *  kmem_cache structure.  Now they may change, say if a high
> +      *  order slab allocation fails, so the per-slab object count
> +      *  is kept in the slab.
> +      */
> +     if (VALID_MEMBER(page_objects)) {
> +             objects_vaddr = page + OFFSET(page_objects);
> +             if (si->flags & SLAB_BITFIELD)
> +                     objects_vaddr += sizeof(ushort);
> +             if (!readmem(objects_vaddr, KVADDR, &objects,
> +                          sizeof(ushort), "page.objects", RETURN_ON_ERROR))
> +                     return 0;
> +             /*
> +              *  Strip page.frozen bit.
> +              */
> +             if (si->flags & SLAB_BITFIELD) {
> +                     if (__BYTE_ORDER == __LITTLE_ENDIAN) {
> +                             objects <<= 1;
> +                             objects >>= 1;
> +                     }
> +                     if (__BYTE_ORDER == __BIG_ENDIAN)
> +                             objects >>= 1;
> +             }
> +
> +             if (CRASHDEBUG(1) && (objects != si->objects))
> +                     error(NOTE, "%s: slab: %lx oo objects: %ld "
> +                           "slab objects: %d\n",
> +                           si->curname, si->slab,
> +                           si->objects, objects);
> +
> +             if (objects == (ushort)(-1)) {
> +                     error(INFO, "%s: slab: %lx invalid page.objects: -1\n",
> +                           si->curname, si->slab);
> +                     return 0;
> +             }
> +     } else
> +             objects = (ushort)si->objects;
> +
> +     return objects;
> +}
> +
>  static short
>  count_cpu_partial(struct meminfo *si, int cpu)
>  {
>       short cpu_partial_inuse, cpu_partial_objects, free_objects;
> -     ulong cpu_partial, objects_vaddr;
> +     ulong cpu_partial;
>  
>       free_objects = 0;
>  
> -     if (VALID_MEMBER(kmem_cache_cpu_partial)) {
> +     if (VALID_MEMBER(kmem_cache_cpu_partial) && VALID_MEMBER(page_objects)) 
> {
>               readmem(ULONG(si->cache_buf + OFFSET(kmem_cache_cpu_slab)) +
>                       kt->__per_cpu_offset[cpu] + 
> OFFSET(kmem_cache_cpu_partial),
>                       KVADDR, &cpu_partial, sizeof(ulong),
> @@ -17939,27 +17986,13 @@ count_cpu_partial(struct meminfo *si, in
>                               return 0;
>                       if (cpu_partial_inuse == -1)
>                               return 0;
> -                     if (VALID_MEMBER(page_objects)) {
> -                             objects_vaddr = cpu_partial + 
> OFFSET(page_objects);
> -                             if (si->flags & SLAB_BITFIELD)
> -                                     objects_vaddr += sizeof(ushort);
> -                             if (!readmem(objects_vaddr, KVADDR,
> -                                 &cpu_partial_objects, sizeof(ushort),
> -                                 "page.objects", RETURN_ON_ERROR))
> -                                     return 0;
> -                             if (si->flags & SLAB_BITFIELD) {
> -                                     if (__BYTE_ORDER == __LITTLE_ENDIAN) {
> -                                             cpu_partial_objects <<= 1;
> -                                             cpu_partial_objects >>= 1;
> -                                     }
> -                                     if (__BYTE_ORDER == __BIG_ENDIAN)
> -                                             cpu_partial_objects >>= 1;
> -                             }
> -                             if (cpu_partial_objects == (short)(-1))
> -                                     return 0;
> -                             free_objects +=
> -                                     cpu_partial_objects - cpu_partial_inuse;
> -                     }
> +
> +                     cpu_partial_objects = slub_page_objects(si,
> +                                                             cpu_partial);
> +                     if (!cpu_partial_objects)
> +                             return 0;
> +                     free_objects += cpu_partial_objects - cpu_partial_inuse;
> +
>                       readmem(cpu_partial + OFFSET(page_next), KVADDR,
>                               &cpu_partial, sizeof(ulong), "page.next",
>                               RETURN_ON_ERROR);
> @@ -18011,14 +18044,12 @@ get_kmem_cache_slub_data(long cmd, struc
>                           KVADDR, &inuse, sizeof(short),
>                           "page inuse", RETURN_ON_ERROR))
>                               return FALSE;
> -                     if (!cpu_freelist)
> -                             if (!readmem(cpu_slab_ptr + 
> OFFSET(page_freelist),
> -                                 KVADDR, &cpu_freelist, sizeof(ulong),
> -                                 "page freelist", RETURN_ON_ERROR))
> -                                     return FALSE;
> +                     objects = slub_page_objects(si, cpu_slab_ptr);
> +                     if (!objects)
> +                             return FALSE;
>  
> -                     free_objects +=
> -                             count_free_objects(si, cpu_freelist);
> +                     free_objects += objects - inuse;
> +                     free_objects += count_free_objects(si, cpu_freelist);
>                       free_objects += count_cpu_partial(si, i);
>  
>                       if (!node_total_avail)
> @@ -18255,7 +18286,7 @@ static int
>  do_slab_slub(struct meminfo *si, int verbose)
>  {
>       physaddr_t paddr;
> -     ulong vaddr, objects_vaddr;
> +     ulong vaddr;
>       ushort inuse, objects;
>       ulong freelist, cpu_freelist, cpu_slab_ptr;
>       int i, free_objects, cpu_slab, is_free, node;
> @@ -18287,50 +18318,17 @@ do_slab_slub(struct meminfo *si, int ver
>       if (!readmem(si->slab + OFFSET(page_freelist), KVADDR, &freelist,
>           sizeof(void *), "page.freelist", RETURN_ON_ERROR))
>               return FALSE;
> -     /*
> -      *  Pre-2.6.27, the object count and order were fixed in the
> -      *  kmem_cache structure.  Now they may change, say if a high
> -      *  order slab allocation fails, so the per-slab object count
> -      *  is kept in the slab.
> -      */
> -     if (VALID_MEMBER(page_objects)) {
> -             objects_vaddr = si->slab + OFFSET(page_objects);
> -             if (si->flags & SLAB_BITFIELD)
> -                     objects_vaddr += sizeof(ushort);
> -             if (!readmem(objects_vaddr, KVADDR, &objects,
> -                 sizeof(ushort), "page.objects", RETURN_ON_ERROR))
> -                     return FALSE;
> -             /*
> -              *  Strip page.frozen bit.
> -              */
> -             if (si->flags & SLAB_BITFIELD) {
> -                     if (__BYTE_ORDER == __LITTLE_ENDIAN) {
> -                             objects <<= 1;
> -                             objects >>= 1;
> -                     }
> -                     if (__BYTE_ORDER == __BIG_ENDIAN)
> -                             objects >>= 1;
> -             }
> -
> -             if (CRASHDEBUG(1) && (objects != si->objects))
> -                     error(NOTE, "%s: slab: %lx oo objects: %ld "
> -                         "slab objects: %d\n",
> -                             si->curname, si->slab,
> -                             si->objects, objects);
>  
> -             if (objects == (ushort)(-1)) {
> -                     error(INFO, "%s: slab: %lx invalid page.objects: -1\n",
> -                             si->curname, si->slab);
> -                     return FALSE;
> -             }
> -     } else
> -             objects = (ushort)si->objects;
> +     objects = slub_page_objects(si, si->slab);
> +     if (!objects)
> +             return FALSE;
>  
>       if (!verbose) {
>               DUMP_SLAB_INFO_SLUB();
>               return TRUE;
>       }
>  
> +     cpu_freelist = 0;
>       for (i = 0, cpu_slab = -1; i < kt->cpus; i++) {
>               cpu_slab_ptr = get_cpu_slab_ptr(si, i, &cpu_freelist);
>  
> @@ -18342,11 +18340,15 @@ do_slab_slub(struct meminfo *si, int ver
>                        *  Later slub scheme uses the per-cpu freelist
>                        *  so count the free objects by hand.
>                        */
> -                     if (cpu_freelist)
> -                             freelist = cpu_freelist;
> -                     if ((free_objects = count_free_objects(si, freelist)) < 
> 0)
> +                     if ((free_objects = count_free_objects(si, 
> cpu_freelist)) < 0)
>                               return FALSE;
> -                     inuse = si->objects - free_objects;
> +                     /*
> +                      * If the object is freed on foreign cpu, the
> +                      * object is liked to page->freelist.
> +                      */
> +                     if (freelist)
> +                             free_objects += objects - inuse;
> +                     inuse = objects - free_objects;
>                       break;
>               }
>       }
> @@ -18377,28 +18379,31 @@ do_slab_slub(struct meminfo *si, int ver
>       for (p = vaddr; p < vaddr + objects * si->size; p += si->size) {
>               hq_open();
>               is_free = FALSE;
> -             for (is_free = 0, q = freelist; q;
> -                     q = get_freepointer(si, (void *)q)) {
> +             /* Search an object on both of freelist and cpu_freelist */
> +             ulong lists[] = { freelist, cpu_freelist, };
> +             for (int i = 0; i < sizeof(lists) / sizeof(lists[0]); i++) {
> +                     for (is_free = 0, q = lists[i]; q;
> +                          q = get_freepointer(si, (void *)q)) {
>  
> -                     if (q == BADADDR) {
> -                             hq_close();
> -                             return FALSE;
> -                     }
> -                     if (q & PAGE_MAPPING_ANON)
> -                             break;
> -                     if (p == q) {
> -                             is_free = TRUE;
> -                             break;
> -                     }
> -                     if (!hq_enter(q)) {
> -                             hq_close();
> -                             error(INFO,
> -                                 "%s: slab: %lx duplicate freelist object: 
> %lx\n",
> -                                     si->curname, si->slab, q);
> -                             return FALSE;
> +                             if (q == BADADDR) {
> +                                     hq_close();
> +                                     return FALSE;
> +                             }
> +                             if (q & PAGE_MAPPING_ANON)
> +                                     break;
> +                             if (p == q) {
> +                                     is_free = TRUE;
> +                                     goto found_object;
> +                             }
> +                             if (!hq_enter(q)) {
> +                                     hq_close();
> +                                     error(INFO, "%s: slab: %lx duplicate 
> freelist object: %lx\n",
> +                                           si->curname, si->slab, q);
> +                                     return FALSE;
> +                             }
>                       }
> -
>               }
> +     found_object:
>               hq_close();
>  
>               if (si->flags & ADDRESS_SPECIFIED) {
> @@ -18677,7 +18682,7 @@ compound_head(ulong page)
>  long
>  count_partial(ulong node, struct meminfo *si, ulong *free)
>  {
> -     ulong list_head, next, last, objects_vaddr;
> +     ulong list_head, next, last;
>       short inuse, objects;
>       ulong total_inuse;
>       ulong count = 0;
> @@ -18708,31 +18713,11 @@ count_partial(ulong node, struct meminfo
>               total_inuse += inuse;
>  
>               if (VALID_MEMBER(page_objects)) {
> -                     objects_vaddr = last + OFFSET(page_objects);
> -                     if (si->flags & SLAB_BITFIELD)
> -                             objects_vaddr += sizeof(ushort);
> -                     if (!readmem(objects_vaddr, KVADDR, &objects,
> -                         sizeof(ushort), "page.objects", RETURN_ON_ERROR)) {
> -                             hq_close();
> -                             return -1;
> -                     }
> -
> -                     if (si->flags & SLAB_BITFIELD) {
> -                             if (__BYTE_ORDER == __LITTLE_ENDIAN) {
> -                                     objects <<= 1;
> -                                     objects >>= 1;
> -                             }
> -                             if (__BYTE_ORDER == __BIG_ENDIAN)
> -                                     objects >>= 1;
> -                     }
> -
> -                     if (objects == (short)(-1)) {
> -                             error(INFO, "%s: slab: %lx invalid 
> page.objects: -1\n",
> -                                     si->curname, last);
> +                     objects = slub_page_objects(si, last);
> +                     if (!objects) {
>                               hq_close();
>                               return -1;
>                       }
> -
>                       *free += objects - inuse;
>               }
>  
> _
> 

--
Crash-utility mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility

Reply via email to