Skip to content

Commit b731e35

Browse files
ftang1tehcaster
authored andcommitted
mm/slub: fix a slab missed to be freed problem
When enable kasan and kfence's in-kernel kunit test with slub_debug on, it caught a problem (in linux-next tree): ------------[ cut here ]------------ kmem_cache_destroy test: Slab cache still has objects when called from test_exit+0x1a/0x30 WARNING: CPU: 3 PID: 240 at mm/slab_common.c:492 kmem_cache_destroy+0x16c/0x170 Modules linked in: CPU: 3 PID: 240 Comm: kunit_try_catch Tainted: G B N 6.0.0-rc7-next-20220929 #52 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 RIP: 0010:kmem_cache_destroy+0x16c/0x170 Code: 41 5c 41 5d e9 a5 04 0b 00 c3 cc cc cc cc 48 8b 55 60 48 8b 4c 24 20 48 c7 c6 40 37 d2 82 48 c7 c7 e8 a0 33 83 e8 4e d7 14 01 <0f> 0b eb a7 41 56 41 89 d6 41 55 49 89 f5 41 54 49 89 fc 55 48 89 RSP: 0000:ffff88800775fea0 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffffffff83bdec48 RCX: 0000000000000000 RDX: 0000000000000001 RSI: 1ffff11000eebf9e RDI: ffffed1000eebfc6 RBP: ffff88804362fa00 R08: ffffffff81182e58 R09: ffff88800775fbdf R10: ffffed1000eebf7b R11: 0000000000000001 R12: 000000008c800d00 R13: ffff888005e78040 R14: 0000000000000000 R15: ffff888005cdfad0 FS: 0000000000000000(0000) GS:ffff88807ed00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000000 CR3: 000000000360e001 CR4: 0000000000370ee0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: <TASK> test_exit+0x1a/0x30 kunit_try_run_case+0xad/0xc0 kunit_generic_run_threadfn_adapter+0x26/0x50 kthread+0x17b/0x1b0 It was biscted to commit c7323a5 ("mm/slub: restrict sysfs validation to debug caches and make it safe") The problem is inside free_debug_processing(), under certain circumstances the slab can be removed from the partial list but not freed by discard_slab() and thus n->nr_slabs is not decreased accordingly. During shutdown, this non-zero n->nr_slabs is detected and reported. Specifically, the problem is that there are two checks for detecting a full partial list by comparing n->nr_partial >= s->min_partial where the latter check is affected by remove_partial() decreasing n->nr_partial between the checks. Reoganize the code so there is a single check upfront. Link: https://lore.kernel.org/all/20220930100730.250248-1-feng.tang@intel.com/ Fixes: c7323a5 ("mm/slub: restrict sysfs validation to debug caches and make it safe") Signed-off-by: Feng Tang <feng.tang@intel.com> Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
1 parent 1f04b07 commit b731e35

File tree

1 file changed

+14
-11
lines changed

1 file changed

+14
-11
lines changed

mm/slub.c

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2836,22 +2836,25 @@ static noinline void free_debug_processing(
28362836
set_freepointer(s, tail, prior);
28372837
slab->freelist = head;
28382838

2839-
/* Do we need to remove the slab from full or partial list? */
2839+
/*
2840+
* If the slab is empty, and node's partial list is full,
2841+
* it should be discarded anyway no matter it's on full or
2842+
* partial list.
2843+
*/
2844+
if (slab->inuse == 0 && n->nr_partial >= s->min_partial)
2845+
slab_free = slab;
2846+
28402847
if (!prior) {
2848+
/* was on full list */
28412849
remove_full(s, n, slab);
2842-
} else if (slab->inuse == 0 &&
2843-
n->nr_partial >= s->min_partial) {
2850+
if (!slab_free) {
2851+
add_partial(n, slab, DEACTIVATE_TO_TAIL);
2852+
stat(s, FREE_ADD_PARTIAL);
2853+
}
2854+
} else if (slab_free) {
28442855
remove_partial(n, slab);
28452856
stat(s, FREE_REMOVE_PARTIAL);
28462857
}
2847-
2848-
/* Do we need to discard the slab or add to partial list? */
2849-
if (slab->inuse == 0 && n->nr_partial >= s->min_partial) {
2850-
slab_free = slab;
2851-
} else if (!prior) {
2852-
add_partial(n, slab, DEACTIVATE_TO_TAIL);
2853-
stat(s, FREE_ADD_PARTIAL);
2854-
}
28552858
}
28562859

28572860
if (slab_free) {

0 commit comments

Comments
 (0)