[PATCH] sched/topology: don't claim sched_domain_shared twice on the same domain
From: Breno Leitao
Date: Mon Aug 10 2026 - 07:55:01 EST
build_sched_domains() lets the asymmetric capacity path claim a
sched_domain_shared object on the lowest SD_ASYM_CPUCAPACITY_FULL
ancestor, and then unconditionally claims one for the topmost
SD_SHARE_LLC domain. When those are the same sched_domain - a system
whose single LLC spans CPUs of differing capacity, for example an arm64
machine with one MC domain covering every CPU - init_sched_domain_shared()
runs twice on that domain. The second call overwrites sd->shared without
dropping the reference the first call took, so the asym blob ends up with
a refcount equal to the CPU count and nothing pointing at it.
claim_allocations() sees the non-zero refcount and clears the per-CPU
slot, so __sds_free() does not reclaim it either, and the object leaks.
kmemleak reports one 32-byte object per build_sched_domains() call:
unreferenced object 0xffff0000c02432a0 (size 32):
comm "swapper/0", pid 1, jiffies 4294667436
hex dump (first 32 bytes):
08 00 00 00 08 00 00 00 00 00 00 00 20 00 00 00 ............ ...
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
backtrace (crc f4478cb7):
kmemleak_alloc+0x44/0xd8
__kmalloc_cache_node_noprof+0x344/0x5d0
build_sched_domains+0x2f8/0x2110
sched_init_domains+0xec/0x160
sched_init_smp+0x48/0x108
kernel_init_freeable+0x1cc/0x2b8
ref and nr_busy_cpus are both the online CPU count and alloc_flags is
0x20, SD_ASYM_CPUCAPACITY, identifying it as the blob the asym path
claimed.
Only claim a shared object for the LLC domain when the domain does not
already have one. sd_init() zero initialises sd->shared for every domain
it builds, so a non-NULL sd->shared here means the asym path already
claimed this very domain. Cache aware scheduling still finds a shared
object on sd_llc, the same one, covering the same span.
Reproduced under QEMU/virtme-ng on arm64 with two capacity tiers
(capacity-dmips-mhz 0x400 on cpu0-3 and 0x200 on cpu4-7), where the MC
domain spans all CPUs and carries both SD_SHARE_LLC and
SD_ASYM_CPUCAPACITY_FULL. Leaked sched_domain_shared objects reported by
kmemleak, with a kmemleak-test module loaded as a positive control:
before after
after boot 1 0
after 12 rebuilds via CPU hotplug 13 0
That is exactly one leak per build_sched_domains(), and none once the
domain is only claimed once.
Fixes: 9e005ed21152 ("sched/topology: Allow multiple domains to claim sched_domain_shared")
Signed-off-by: Breno Leitao <leitao@xxxxxxxxxx>
---
The hunk context is identical in v7.2-rc7 and in current linux-next, so
this applies cleanly to both.
---
kernel/sched/topology.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c
index 5a29e506c25d5..206552d51ce2e 100644
--- a/kernel/sched/topology.c
+++ b/kernel/sched/topology.c
@@ -3169,7 +3169,13 @@ build_sched_domains(const struct cpumask *cpu_map, struct sched_domain_attr *att
sd = sd->parent;
if (sd->flags & SD_SHARE_LLC) {
- init_sched_domain_shared(&d, sd, SD_SHARE_LLC);
+ /*
+ * The asym path above may have claimed a shared object
+ * on this very domain; claiming it again overwrites
+ * sd->shared and leaks the first reference.
+ */
+ if (!sd->shared)
+ init_sched_domain_shared(&d, sd, SD_SHARE_LLC);
/*
* In presence of higher domains, adjust the
---
base-commit: 6b8c8af514d739d0335f5579b585e02babe8a727
change-id: 20260810-b4-sched_shared_leak-fbaf6cbe0b24
Best regards,
--
Breno Leitao <leitao@xxxxxxxxxx>