Skip to content

Commit 213c5a4

Browse files
Shu WangIngo Molnar
authored andcommitted
sched/topology: Fix memory leak in __sdt_alloc()
Found this issue by kmemleak: the 'sg' and 'sgc' pointers from __sdt_alloc() might be leaked as each domain holds many groups' ref, but in destroy_sched_domain(), it only declined the first group ref. Onlining and offlining a CPU can trigger this leak, and cause OOM. Reproducer for my 6 CPUs machine: while true do echo 0 > /sys/devices/system/cpu/cpu5/online; echo 1 > /sys/devices/system/cpu/cpu5/online; done unreferenced object 0xffff88007d772a80 (size 64): comm "cpuhp/5", pid 39, jiffies 4294719962 (age 35.251s) hex dump (first 32 bytes): c0 22 77 7d 00 88 ff ff 02 00 00 00 01 00 00 00 ."w}............ 40 2a 77 7d 00 88 ff ff 00 00 00 00 00 00 00 00 @*w}............ backtrace: [<ffffffff8176525a>] kmemleak_alloc+0x4a/0xa0 [<ffffffff8121efe1>] __kmalloc_node+0xf1/0x280 [<ffffffff810d94a8>] build_sched_domains+0x1e8/0xf20 [<ffffffff810da674>] partition_sched_domains+0x304/0x360 [<ffffffff81139557>] cpuset_update_active_cpus+0x17/0x40 [<ffffffff810bdb2e>] sched_cpu_activate+0xae/0xc0 [<ffffffff810900e0>] cpuhp_invoke_callback+0x90/0x400 [<ffffffff81090597>] cpuhp_up_callbacks+0x37/0xb0 [<ffffffff81090887>] cpuhp_thread_fun+0xd7/0xf0 [<ffffffff810b37e0>] smpboot_thread_fn+0x110/0x160 [<ffffffff810af5d9>] kthread+0x109/0x140 [<ffffffff81770e45>] ret_from_fork+0x25/0x30 [<ffffffffffffffff>] 0xffffffffffffffff unreferenced object 0xffff88007d772a40 (size 64): comm "cpuhp/5", pid 39, jiffies 4294719962 (age 35.251s) hex dump (first 32 bytes): 03 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 ................ 00 04 00 00 00 00 00 00 4f 3c fc ff 00 00 00 00 ........O<...... backtrace: [<ffffffff8176525a>] kmemleak_alloc+0x4a/0xa0 [<ffffffff8121efe1>] __kmalloc_node+0xf1/0x280 [<ffffffff810da16d>] build_sched_domains+0xead/0xf20 [<ffffffff810da674>] partition_sched_domains+0x304/0x360 [<ffffffff81139557>] cpuset_update_active_cpus+0x17/0x40 [<ffffffff810bdb2e>] sched_cpu_activate+0xae/0xc0 [<ffffffff810900e0>] cpuhp_invoke_callback+0x90/0x400 [<ffffffff81090597>] cpuhp_up_callbacks+0x37/0xb0 [<ffffffff81090887>] cpuhp_thread_fun+0xd7/0xf0 [<ffffffff810b37e0>] smpboot_thread_fn+0x110/0x160 [<ffffffff810af5d9>] kthread+0x109/0x140 [<ffffffff81770e45>] ret_from_fork+0x25/0x30 [<ffffffffffffffff>] 0xffffffffffffffff Reported-by: Chunyu Hu <[email protected]> Signed-off-by: Shu Wang <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Acked-by: Chunyu Hu <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: [email protected] Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 3a9ff4f commit 213c5a4

File tree

1 file changed

+7
-9
lines changed

1 file changed

+7
-9
lines changed

kernel/sched/topology.c

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -335,23 +335,20 @@ static void free_sched_groups(struct sched_group *sg, int free_sgc)
335335
if (free_sgc && atomic_dec_and_test(&sg->sgc->ref))
336336
kfree(sg->sgc);
337337

338-
kfree(sg);
338+
if (atomic_dec_and_test(&sg->ref))
339+
kfree(sg);
339340
sg = tmp;
340341
} while (sg != first);
341342
}
342343

343344
static void destroy_sched_domain(struct sched_domain *sd)
344345
{
345346
/*
346-
* If its an overlapping domain it has private groups, iterate and
347-
* nuke them all.
347+
* A sched domain has many groups' reference, and an overlapping
348+
* domain has private groups, iterate and nuke them all.
348349
*/
349-
if (sd->flags & SD_OVERLAP) {
350-
free_sched_groups(sd->groups, 1);
351-
} else if (atomic_dec_and_test(&sd->groups->ref)) {
352-
kfree(sd->groups->sgc);
353-
kfree(sd->groups);
354-
}
350+
free_sched_groups(sd->groups, 1);
351+
355352
if (sd->shared && atomic_dec_and_test(&sd->shared->ref))
356353
kfree(sd->shared);
357354
kfree(sd);
@@ -668,6 +665,7 @@ build_group_from_child_sched_domain(struct sched_domain *sd, int cpu)
668665
else
669666
cpumask_copy(sg_span, sched_domain_span(sd));
670667

668+
atomic_inc(&sg->ref);
671669
return sg;
672670
}
673671

0 commit comments

Comments
 (0)