Re: kmemleak: sched_domain_shared leaked on asymmetric-capacity + SCHED_CACHE

From: K Prateek Nayak

Date: Sat Jul 04 2026 - 02:16:23 EST


Hello Breno,

On 7/3/2026 9:49 PM, Breno Leitao wrote:
> Hello Prateek,
>
> On Fri, Jul 03, 2026 at 04:05:59PM +0530, K Prateek Nayak wrote:
>> On 7/3/2026 3:52 PM, Breno Leitao wrote:
>>> On current linux-next (CONFIG_SCHED_CACHE=y) we hit a kmemleak on an
>>> arm64 box with asymmetric CPU capacity, triggered by a cpuset-driven
>>> sched-domain rebuild:
>>>
>>> kmemleak: unreferenced object 0xffff000100c95e80 (size 32):
>>> comm "kworker/22:1", pid 407, jiffies 4294669077
>>> hex dump (first 32 bytes):
>>> 48 00 00 00 48 00 00 00 00 00 00 00 20 00 00 00 H...H....... ...
>>> backtrace (crc ec5d7053):
>>> __kmalloc_cache_node_noprof
>>> build_sched_domains
>>> partition_sched_domains
>>> rebuild_sched_domains_locked
>>> rebuild_sched_domains
>>> process_scheduled_works
>>> kthread
>>> ret_from_fork
>>> kmemleak: 1 new suspected memory leaks
>>>
>>> The leaked object is a struct sched_domain_shared (32 bytes with
>>> CONFIG_SCHED_CACHE) allocated in __sds_alloc(), inlined into
>>> build_sched_domains()
>>>
>>> Is this a known issue?
>>
>> It is theoretically possible but there is a defensive WARN_ON()
>> in topology code that you should have hit first. Do you see any
>> other warning?
>>
>> If it is not too much trouble, could you add "sched_verbose"
>> to your kernel cmdline (or do
>> echo Y > /sys/kernel/debug/sched/verbose) and redo this cpuset
>> that leaks the data and share the dmesg. It should give some clue
>> what the topology looks like that causes this.
>
> Sure, does this one help:

Unfortunately no! This doesn't give the span and capacity
information so I cannot really tell what kind of topology
actually triggers this.

Ideally, you enable verbose logging, do the cpuset operation
that leaks the object, and then save the demesg after which
will have a complete topology for all CPUs there including
their capacities and we can piece together a qemu environment
to debug where it all went wrong.

>
>
>
> bash-5.1# cat /sys/kernel/debug/kmemleak
> unreferenced object 0xffff0000c1180820 (size 32):
> comm "swapper/0", pid 1, jiffies 4294667323
> 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/0x5d8
> build_sched_domains+0x2f8/0x2110
> sched_init_domains+0xec/0x160
> sched_init_smp+0x48/0x108
> kernel_init_freeable+0x140/0x200
> kernel_init+0x30/0x170
> ret_from_fork+0x10/0x20
>
> bash-5.1# cd /sys/kernel/debug/sched/domains/
>
> bash-5.1# grep . -r *
> cpu0/domain0/level:1
> cpu0/domain0/flags:SD_BALANCE_NEWIDLE SD_BALANCE_EXEC SD_BALANCE_FORK SD_WAKE_AFFINE SD_ASYM_CPUCAPACITY SD_ASYM_CPUCAPACITY_FULL SD_SHARE_LLC SD_PREFER_SIBLING
> cpu0/domain0/name:MC
> cpu0/domain0/cache_nice_tries:1
> cpu0/domain0/imbalance_pct:117
> cpu0/domain0/busy_factor:16
> cpu0/domain0/max_newidle_lb_cost:2127
> cpu0/domain0/max_interval:16
> cpu0/domain0/min_interval:8
> cpu1/domain0/level:1
> cpu1/domain0/flags:SD_BALANCE_NEWIDLE SD_BALANCE_EXEC SD_BALANCE_FORK SD_WAKE_AFFINE SD_ASYM_CPUCAPACITY SD_ASYM_CPUCAPACITY_FULL SD_SHARE_LLC SD_PREFER_SIBLING
> cpu1/domain0/name:MC
> cpu1/domain0/cache_nice_tries:1
> cpu1/domain0/imbalance_pct:117
> cpu1/domain0/busy_factor:16
> cpu1/domain0/max_newidle_lb_cost:18112
> cpu1/domain0/max_interval:16
> cpu1/domain0/min_interval:8
> cpu2/domain0/level:1
> cpu2/domain0/flags:SD_BALANCE_NEWIDLE SD_BALANCE_EXEC SD_BALANCE_FORK SD_WAKE_AFFINE SD_ASYM_CPUCAPACITY SD_ASYM_CPUCAPACITY_FULL SD_SHARE_LLC SD_PREFER_SIBLING
> cpu2/domain0/name:MC
> cpu2/domain0/cache_nice_tries:1
> cpu2/domain0/imbalance_pct:117
> cpu2/domain0/busy_factor:16
> cpu2/domain0/max_newidle_lb_cost:3147
> cpu2/domain0/max_interval:16
> cpu2/domain0/min_interval:8
> cpu3/domain0/level:1
> cpu3/domain0/flags:SD_BALANCE_NEWIDLE SD_BALANCE_EXEC SD_BALANCE_FORK SD_WAKE_AFFINE SD_ASYM_CPUCAPACITY SD_ASYM_CPUCAPACITY_FULL SD_SHARE_LLC SD_PREFER_SIBLING
> cpu3/domain0/name:MC
> cpu3/domain0/cache_nice_tries:1
> cpu3/domain0/imbalance_pct:117
> cpu3/domain0/busy_factor:16
> cpu3/domain0/max_newidle_lb_cost:16399
> cpu3/domain0/max_interval:16
> cpu3/domain0/min_interval:8
> cpu4/domain0/level:1
> cpu4/domain0/flags:SD_BALANCE_NEWIDLE SD_BALANCE_EXEC SD_BALANCE_FORK SD_WAKE_AFFINE SD_ASYM_CPUCAPACITY SD_ASYM_CPUCAPACITY_FULL SD_SHARE_LLC SD_PREFER_SIBLING
> cpu4/domain0/name:MC
> cpu4/domain0/cache_nice_tries:1
> cpu4/domain0/imbalance_pct:117
> cpu4/domain0/busy_factor:16
> cpu4/domain0/max_newidle_lb_cost:27180
> cpu4/domain0/max_interval:16
> cpu4/domain0/min_interval:8
> cpu5/domain0/level:1
> cpu5/domain0/flags:SD_BALANCE_NEWIDLE SD_BALANCE_EXEC SD_BALANCE_FORK SD_WAKE_AFFINE SD_ASYM_CPUCAPACITY SD_ASYM_CPUCAPACITY_FULL SD_SHARE_LLC SD_PREFER_SIBLING
> cpu5/domain0/name:MC
> cpu5/domain0/cache_nice_tries:1
> cpu5/domain0/imbalance_pct:117
> cpu5/domain0/busy_factor:16
> cpu5/domain0/max_newidle_lb_cost:18384
> cpu5/domain0/max_interval:16
> cpu5/domain0/min_interval:8
> cpu6/domain0/level:1
> cpu6/domain0/flags:SD_BALANCE_NEWIDLE SD_BALANCE_EXEC SD_BALANCE_FORK SD_WAKE_AFFINE SD_ASYM_CPUCAPACITY SD_ASYM_CPUCAPACITY_FULL SD_SHARE_LLC SD_PREFER_SIBLING
> cpu6/domain0/name:MC
> cpu6/domain0/cache_nice_tries:1
> cpu6/domain0/imbalance_pct:117
> cpu6/domain0/busy_factor:16
> cpu6/domain0/max_newidle_lb_cost:16261
> cpu6/domain0/max_interval:16
> cpu6/domain0/min_interval:8
> cpu7/domain0/level:1
> cpu7/domain0/flags:SD_BALANCE_NEWIDLE SD_BALANCE_EXEC SD_BALANCE_FORK SD_WAKE_AFFINE SD_ASYM_CPUCAPACITY SD_ASYM_CPUCAPACITY_FULL SD_SHARE_LLC SD_PREFER_SIBLING
> cpu7/domain0/name:MC
> cpu7/domain0/cache_nice_tries:1
> cpu7/domain0/imbalance_pct:117
> cpu7/domain0/busy_factor:16
> cpu7/domain0/max_newidle_lb_cost:7780
> cpu7/domain0/max_interval:16
> cpu7/domain0/min_interval:8

Is this the defualt topology before the cpuset? Because
min_interval of 8 means there are 8 cPUs in the span and
you have 8 CPUs in your machine so there seems to be a
single root partition when you captured this.

Also does your dmesg have any warnings from topology.c?

The only way I can see this triggering is there is a single
cpu SD_SHARE_LLC at top which claims all the sd->shared and
then you get a SD_ASYM_CPUCAPACITY_FULL on top which too
tries to claim a sd->shared but all are already gone.

Afaict, all CPUs in your system are on single LLC and you
can't SD_ASYM_CPUCAPACITY_FULL without having more than one
capacity in the span so I'm at a loss currently as to how
this reference gets dropped without being freed.

--
Thanks and Regards,
Prateek