Skip to content

Commit

Permalink
SLUB: Fix for offset change of struct slab members on Linux 6.2-rc1
Browse files Browse the repository at this point in the history
The following kernel commits split slab info from struct page into
struct slab in Linux 5.17.

  d122019bf061 ("mm: Split slab into its own type")
  07f910f9b729 ("mm: Remove slab from struct page")

Crash commit 5f390ed followed the change for SLUB, but crash still
uses the offset of page.lru inappropriately.  Luckily, it could work
because it was the same value as the offset of slab.slab_list until
Linux 6.1.

However, kernel commit 130d4df57390 ("mm/sl[au]b: rearrange struct slab
fields to allow larger rcu_head") in Linux 6.2-rc1 changed the offset of
slab.slab_list.  As a result, without the patch, "kmem -s|-S" options
print the following errors and fail to print values correctly for
kernels configured with CONFIG_SLUB.

  crash> kmem -S filp
  CACHE             OBJSIZE  ALLOCATED     TOTAL  SLABS  SSIZE  NAME
  kmem: filp: partial list slab: ffffcc650405ab88 invalid page.inuse: -1
  ffff8fa0401eca00      232       1267      1792     56     8k  filp
  ...
  KMEM_CACHE_NODE   NODE  SLABS  PARTIAL  PER-CPU
  ffff8fa0401cb8c0     0     56       24        8
  NODE 0 PARTIAL:
    SLAB              MEMORY            NODE  TOTAL  ALLOCATED  FREE
  kmem: filp: invalid partial list slab pointer: ffffcc650405ab88

Signed-off-by: Kazuhito Hagio <k-hagio-ab@nec.com>
  • Loading branch information
k-hagio committed Dec 26, 2022
1 parent 0d5ad12 commit d83df2f
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 6 deletions.
1 change: 1 addition & 0 deletions defs.h
Expand Up @@ -2188,6 +2188,7 @@ struct offset_table { /* stash of commonly-used offsets */
long blk_mq_tags_rqs;
long request_queue_hctx_table;
long percpu_counter_counters;
long slab_slab_list;
};

struct size_table { /* stash of commonly-used sizes */
Expand Down
16 changes: 10 additions & 6 deletions memory.c
Expand Up @@ -781,6 +781,8 @@ vm_init(void)
if (INVALID_MEMBER(page_slab))
MEMBER_OFFSET_INIT(page_slab, "slab", "slab_cache");

MEMBER_OFFSET_INIT(slab_slab_list, "slab", "slab_list");

MEMBER_OFFSET_INIT(page_slab_page, "page", "slab_page");
if (INVALID_MEMBER(page_slab_page))
ANON_MEMBER_OFFSET_INIT(page_slab_page, "page", "slab_page");
Expand Down Expand Up @@ -19474,6 +19476,7 @@ do_node_lists_slub(struct meminfo *si, ulong node_ptr, int node)
{
ulong next, last, list_head, flags;
int first;
long list_off = VALID_MEMBER(slab_slab_list) ? OFFSET(slab_slab_list) : OFFSET(page_lru);

if (!node_ptr)
return;
Expand All @@ -19487,7 +19490,7 @@ do_node_lists_slub(struct meminfo *si, ulong node_ptr, int node)
next == list_head ? " (empty)\n" : "");
first = 0;
while (next != list_head) {
si->slab = last = next - OFFSET(page_lru);
si->slab = last = next - list_off;
if (first++ == 0)
fprintf(fp, " %s", slab_hdr);

Expand All @@ -19510,7 +19513,7 @@ do_node_lists_slub(struct meminfo *si, ulong node_ptr, int node)

if (!IS_KVADDR(next) ||
((next != list_head) &&
!is_page_ptr(next - OFFSET(page_lru), NULL))) {
!is_page_ptr(next - list_off, NULL))) {
error(INFO,
"%s: partial list slab: %lx invalid page.lru.next: %lx\n",
si->curname, last, next);
Expand All @@ -19537,7 +19540,7 @@ do_node_lists_slub(struct meminfo *si, ulong node_ptr, int node)
next == list_head ? " (empty)\n" : "");
first = 0;
while (next != list_head) {
si->slab = next - OFFSET(page_lru);
si->slab = next - list_off;
if (first++ == 0)
fprintf(fp, " %s", slab_hdr);

Expand Down Expand Up @@ -19754,6 +19757,7 @@ count_partial(ulong node, struct meminfo *si, ulong *free)
short inuse, objects;
ulong total_inuse;
ulong count = 0;
long list_off = VALID_MEMBER(slab_slab_list) ? OFFSET(slab_slab_list) : OFFSET(page_lru);

count = 0;
total_inuse = 0;
Expand All @@ -19765,12 +19769,12 @@ count_partial(ulong node, struct meminfo *si, ulong *free)
hq_open();

while (next != list_head) {
if (!readmem(next - OFFSET(page_lru) + OFFSET(page_inuse),
if (!readmem(next - list_off + OFFSET(page_inuse),
KVADDR, &inuse, sizeof(ushort), "page.inuse", RETURN_ON_ERROR)) {
hq_close();
return -1;
}
last = next - OFFSET(page_lru);
last = next - list_off;

if (inuse == -1) {
error(INFO,
Expand All @@ -19796,7 +19800,7 @@ count_partial(ulong node, struct meminfo *si, ulong *free)
}
if (!IS_KVADDR(next) ||
((next != list_head) &&
!is_page_ptr(next - OFFSET(page_lru), NULL))) {
!is_page_ptr(next - list_off, NULL))) {
error(INFO, "%s: partial list slab: %lx invalid page.lru.next: %lx\n",
si->curname, last, next);
break;
Expand Down
1 change: 1 addition & 0 deletions symbols.c
Expand Up @@ -9710,6 +9710,7 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(slab_inuse));
fprintf(fp, " slab_free: %ld\n",
OFFSET(slab_free));
fprintf(fp, " slab_slab_list: %ld\n", OFFSET(slab_slab_list));

fprintf(fp, " kmem_cache_size: %ld\n",
OFFSET(kmem_cache_size));
Expand Down

0 comments on commit d83df2f

Please sign in to comment.