Skip to content

Commit

Permalink
Fix for Linux 4.6 commit b03a017bebc403d40aa53a092e79b3020786537d,
Browse files Browse the repository at this point in the history
which introduced the new slab management type OBJFREELIST_SLAB.
In this mode, the freelist can be an object, and if the slab is full,
there is no freelist.  On the next free, an object is recycled to be
used as the freelist but not cleaned-up.  This patch will go through
only known freed objects, and will prevent "kmem -S" errors that
indicate "invalid/corrupt freelist entry" on kernels configured
with CONFIG_SLAB.
(thgarnie@google.com)
  • Loading branch information
Dave Anderson committed Dec 2, 2016
1 parent 01e6fa2 commit 59fbaf3
Showing 1 changed file with 24 additions and 6 deletions.
30 changes: 24 additions & 6 deletions memory.c
Expand Up @@ -9880,6 +9880,7 @@ ignore_cache(struct meminfo *si, char *name)
#define SLAB_MAGIC_DESTROYED 0xB2F23C5AUL /* slab has been destroyed */

#define SLAB_CFLGS_BUFCTL 0x020000UL /* bufctls in own cache */
#define SLAB_CFLGS_OBJFREELIST 0x40000000UL /* Freelist as an object */

#define KMEM_SLAB_ADDR (1)
#define KMEM_BUFCTL_ADDR (2)
Expand Down Expand Up @@ -12439,11 +12440,13 @@ gather_slab_free_list_percpu(struct meminfo *si)
static void
gather_slab_free_list_slab_overload_page(struct meminfo *si)
{
int i, active;
int i, active, start_offset;
ulong obj, objnr, cnt, freelist;
unsigned char *ucharptr;
unsigned short *ushortptr;
unsigned int *uintptr;
unsigned int cache_flags, overload_active;
ulong slab_overload_page;

if (CRASHDEBUG(1))
fprintf(fp, "slab page: %lx active: %ld si->c_num: %ld\n",
Expand All @@ -12452,12 +12455,19 @@ gather_slab_free_list_slab_overload_page(struct meminfo *si)
if (si->s_inuse == si->c_num )
return;

readmem(si->slab - OFFSET(page_lru) + OFFSET(page_freelist),
slab_overload_page = si->slab - OFFSET(page_lru);
readmem(slab_overload_page + OFFSET(page_freelist),
KVADDR, &freelist, sizeof(void *), "page freelist",
FAULT_ON_ERROR);
readmem(freelist, KVADDR, si->freelist,
si->freelist_index_size * si->c_num,
"freelist array", FAULT_ON_ERROR);
readmem(si->cache+OFFSET(kmem_cache_s_flags),
KVADDR, &cache_flags, sizeof(uint),
"kmem_cache_s flags", FAULT_ON_ERROR);
readmem(slab_overload_page + OFFSET(page_active),
KVADDR, &overload_active, sizeof(uint),
"active", FAULT_ON_ERROR);

BNEG(si->addrlist, sizeof(ulong) * (si->c_num+1));
cnt = objnr = 0;
Expand All @@ -12466,14 +12476,22 @@ gather_slab_free_list_slab_overload_page(struct meminfo *si)
uintptr = NULL;
active = si->s_inuse;

/*
* On an OBJFREELIST slab, the object might have been recycled
* and everything before the active count can be random data.
*/
start_offset = 0;
if (cache_flags & SLAB_CFLGS_OBJFREELIST)
start_offset = overload_active;

switch (si->freelist_index_size)
{
case 1: ucharptr = (unsigned char *)si->freelist; break;
case 2: ushortptr = (unsigned short *)si->freelist; break;
case 4: uintptr = (unsigned int *)si->freelist; break;
case 1: ucharptr = (unsigned char *)si->freelist + start_offset; break;
case 2: ushortptr = (unsigned short *)si->freelist + start_offset; break;
case 4: uintptr = (unsigned int *)si->freelist + start_offset; break;
}

for (i = 0; i < si->c_num; i++) {
for (i = start_offset; i < si->c_num; i++) {
switch (si->freelist_index_size)
{
case 1: objnr = (ulong)*ucharptr++; break;
Expand Down

0 comments on commit 59fbaf3

Please sign in to comment.