* [PATCH] sched/topology: fix memory leaks in allocation failure paths
@ 2026-07-09 23:03 monios114514
2026-08-14 13:56 ` kernel test robot
0 siblings, 1 reply; 2+ messages in thread
From: monios114514 @ 2026-07-09 23:03 UTC (permalink / raw)
To: mingo@redhat.com
Cc: peterz@infradead.org, juri.lelli@redhat.com,
vincent.guittot@linaro.org, dietmar.eggemann@arm.com,
rostedt@goodmis.org, bsegall@google.com, mgorman@suse.de,
vschneid@redhat.com, kprateek.nayak@amd.com,
linux-kernel@vger.kernel.org
From c58bc2361ab78a5d978a3962dd9e88089a09d11b Mon Sep 17 00:00:00 2001
From: cpumsconfig <monios114514@outlook.com>
Date: Thu, 9 Jul 2026 21:58:41 +0800
Subject: [PATCH] sched/topology: fix memory leaks in allocation failure paths
Fix three memory leaks in the scheduler topology code when memory
allocation fails:
1. sched_init_numa(): When per-node masks[i] or inner mask allocation
fails, previously allocated masks[0..i-1] and the masks array itself
are not freed before return. The separately allocated domain_distances
also leaks.
2. __sdt_alloc(): When per-CPU sd/sg/sgc allocation fails in the inner
loop, already allocated per-CPU pointers for completed CPUs leak.
Fix by using a unified fail label that calls __sdt_free().
3. __sds_alloc(): When percpu d->sds allocation succeeds but inner
kzalloc_node fails, d->sds leaks. Fix by calling __sds_free().
Signed-off-by: cpumsconfig <monios114514@outlook.com>
---
kernel/sched/topology.c | 99 ++++++++++++++++++++++-------------------
1 file changed, 53 insertions(+), 46 deletions(-)
diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c
index 622e2e019..fb5200b58 100644
--- a/kernel/sched/topology.c
+++ b/kernel/sched/topology.c
@@ -2320,12 +2320,10 @@ void sched_init_numa(int offline_node)
int *distances, *domain_distances;
struct cpumask ***masks;
- /* Record the NUMA distances from SLIT table */
if (sched_record_numa_dist(offline_node, numa_node_dist, &distances,
&nr_node_levels))
return;
- /* Record modified NUMA distances for building sched domains */
if (modified_sched_node_distance()) {
if (sched_record_numa_dist(offline_node, arch_sched_node_distance,
&domain_distances, &nr_levels)) {
@@ -2340,45 +2338,43 @@ void sched_init_numa(int offline_node)
WRITE_ONCE(sched_max_numa_distance, distances[nr_node_levels - 1]);
WRITE_ONCE(sched_numa_node_levels, nr_node_levels);
- /*
- * 'nr_levels' contains the number of unique distances
- *
- * The sched_domains_numa_distance[] array includes the actual distance
- * numbers.
- */
-
- /*
- * Here, we should temporarily reset sched_domains_numa_levels to 0.
- * If it fails to allocate memory for array sched_domains_numa_masks[][],
- * the array will contain less then 'nr_levels' members. This could be
- * dangerous when we use it to iterate array sched_domains_numa_masks[][]
- * in other functions.
- *
- * We reset it to 'nr_levels' at the end of this function.
- */
rcu_assign_pointer(sched_domains_numa_distance, domain_distances);
sched_domains_numa_levels = 0;
masks = kzalloc(sizeof(void *) * nr_levels, GFP_KERNEL);
if (!masks)
- return;
+ goto free_distance;
- /*
- * Now for each level, construct a mask per node which contains all
- * CPUs of nodes that are that many hops away from us.
- */
for (i = 0; i < nr_levels; i++) {
masks[i] = kzalloc(nr_node_ids * sizeof(void *), GFP_KERNEL);
- if (!masks[i])
- return;
+ if (!masks[i]) {
+ for (i = i - 1; i >= 0; i--) {
+ if (!masks[i])
+ continue;
+ for_each_cpu_node_but(j, offline_node)
+ kfree(masks[i][j]);
+ kfree(masks[i]);
+ }
+ kfree(masks);
+ goto free_distance;
+ }
for_each_cpu_node_but(j, offline_node) {
struct cpumask *mask = kzalloc(cpumask_size(), GFP_KERNEL);
int k;
- if (!mask)
- return;
+ if (!mask) {
+ for (i = i; i >= 0; i--) {
+ if (!masks[i])
+ continue;
+ for_each_cpu_node_but(j, offline_node)
+ kfree(masks[i][j]);
+ kfree(masks[i]);
+ }
+ kfree(masks);
+ goto free_distance;
+ }
masks[i][j] = mask;
@@ -2398,28 +2394,28 @@ void sched_init_numa(int offline_node)
}
rcu_assign_pointer(sched_domains_numa_masks, masks);
- /* Compute default topology size */
for (i = 0; sched_domain_topology[i].mask; i++);
tl = kzalloc((i + nr_levels + 1) *
sizeof(struct sched_domain_topology_level), GFP_KERNEL);
- if (!tl)
- return;
+ if (!tl) {
+ rcu_assign_pointer(sched_domains_numa_masks, NULL);
+ for (i = nr_levels - 1; i >= 0; i--) {
+ if (!masks[i])
+ continue;
+ for_each_cpu_node_but(j, offline_node)
+ kfree(masks[i][j]);
+ kfree(masks[i]);
+ }
+ kfree(masks);
+ goto free_distance;
+ }
- /*
- * Copy the default topology bits..
- */
for (i = 0; sched_domain_topology[i].mask; i++)
tl[i] = sched_domain_topology[i];
- /*
- * Add the NUMA identity distance, aka single NODE.
- */
tl[i++] = SDTL_INIT(sd_numa_mask, NULL, NODE);
- /*
- * .. and append 'j' levels of NUMA goodness.
- */
for (j = 1; j < nr_levels; i++, j++) {
tl[i] = SDTL_INIT(sd_numa_mask, cpu_numa_flags, NUMA);
tl[i].numa_level = j;
@@ -2431,6 +2427,11 @@ void sched_init_numa(int offline_node)
sched_domains_numa_levels = nr_levels;
init_numa_topology_type(offline_node);
+ return;
+
+free_distance:
+ if (domain_distances != distances)
+ kfree(domain_distances);
}
@@ -2670,15 +2671,15 @@ static int __sdt_alloc(const struct cpumask *cpu_map)
sdd->sd = alloc_percpu(struct sched_domain *);
if (!sdd->sd)
- return -ENOMEM;
+ goto fail;
sdd->sg = alloc_percpu(struct sched_group *);
if (!sdd->sg)
- return -ENOMEM;
+ goto fail;
sdd->sgc = alloc_percpu(struct sched_group_capacity *);
if (!sdd->sgc)
- return -ENOMEM;
+ goto fail;
for_each_cpu(j, cpu_map) {
struct sched_domain *sd;
@@ -2688,14 +2689,14 @@ static int __sdt_alloc(const struct cpumask *cpu_map)
sd = kzalloc_node(sizeof(struct sched_domain) + cpumask_size(),
GFP_KERNEL, cpu_to_node(j));
if (!sd)
- return -ENOMEM;
+ goto fail;
*per_cpu_ptr(sdd->sd, j) = sd;
sg = kzalloc_node(sizeof(struct sched_group) + cpumask_size(),
GFP_KERNEL, cpu_to_node(j));
if (!sg)
- return -ENOMEM;
+ goto fail;
sg->next = sg;
@@ -2704,7 +2705,7 @@ static int __sdt_alloc(const struct cpumask *cpu_map)
sgc = kzalloc_node(sizeof(struct sched_group_capacity) + cpumask_size(),
GFP_KERNEL, cpu_to_node(j));
if (!sgc)
- return -ENOMEM;
+ goto fail;
sgc->id = j;
@@ -2713,6 +2714,10 @@ static int __sdt_alloc(const struct cpumask *cpu_map)
}
return 0;
+
+fail:
+ __sdt_free(cpu_map);
+ return -ENOMEM;
}
static void __sdt_free(const struct cpumask *cpu_map)
@@ -2760,8 +2765,10 @@ static int __sds_alloc(struct s_data *d, const struct cpumask *cpu_map)
sds = kzalloc_node(sizeof(struct sched_domain_shared),
GFP_KERNEL, cpu_to_node(j));
- if (!sds)
+ if (!sds) {
+ __sds_free(d, cpu_map);
return -ENOMEM;
+ }
*per_cpu_ptr(d->sds, j) = sds;
}
--
2.54.0.windows.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] sched/topology: fix memory leaks in allocation failure paths
2026-07-09 23:03 [PATCH] sched/topology: fix memory leaks in allocation failure paths monios114514
@ 2026-08-14 13:56 ` kernel test robot
0 siblings, 0 replies; 2+ messages in thread
From: kernel test robot @ 2026-08-14 13:56 UTC (permalink / raw)
To: monios114514@outlook.com, mingo@redhat.com
Cc: llvm, oe-kbuild-all, peterz@infradead.org, juri.lelli@redhat.com,
vincent.guittot@linaro.org, dietmar.eggemann@arm.com,
rostedt@goodmis.org, bsegall@google.com, mgorman@suse.de,
vschneid@redhat.com, kprateek.nayak@amd.com,
linux-kernel@vger.kernel.org
Hi,
kernel test robot noticed the following build warnings:
[auto build test WARNING on tip/sched/core]
[also build test WARNING on peterz-queue/sched/core linus/master v7.2-rc7 next-20260813]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/monios114514-outlook-com/sched-topology-fix-memory-leaks-in-allocation-failure-paths/20260813-171714
base: tip/sched/core
patch link: https://lore.kernel.org/r/SL2P216MB261965EB5BCCF15723D13A76C1FE2%40SL2P216MB2619.KORP216.PROD.OUTLOOK.COM
patch subject: [PATCH] sched/topology: fix memory leaks in allocation failure paths
config: riscv-randconfig-002-20260814 (https://download.01.org/0day-ci/archive/20260814/202608142104.E7fmtysw-lkp@intel.com/config)
compiler: clang version 24.0.0git (https://github.com/llvm/llvm-project 844a18e753e822736c9805ab779144b647a2c186)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260814/202608142104.E7fmtysw-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202608142104.E7fmtysw-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from kernel/sched/build_utility.c:86:
>> kernel/sched/topology.c:2364:12: warning: explicitly assigning value of variable of type 'int' to itself [-Wself-assign]
2364 | for (i = i; i >= 0; i--) {
| ~ ^ ~
1 warning generated.
vim +/int +2364 kernel/sched/topology.c
2310
2311 void sched_init_numa(int offline_node)
2312 {
2313 struct sched_domain_topology_level *tl;
2314 int nr_levels, nr_node_levels;
2315 int i, j;
2316 int *distances, *domain_distances;
2317 struct cpumask ***masks;
2318
2319 if (sched_record_numa_dist(offline_node, numa_node_dist, &distances,
2320 &nr_node_levels))
2321 return;
2322
2323 if (modified_sched_node_distance()) {
2324 if (sched_record_numa_dist(offline_node, arch_sched_node_distance,
2325 &domain_distances, &nr_levels)) {
2326 kfree(distances);
2327 return;
2328 }
2329 } else {
2330 domain_distances = distances;
2331 nr_levels = nr_node_levels;
2332 }
2333 rcu_assign_pointer(sched_numa_node_distance, distances);
2334 WRITE_ONCE(sched_max_numa_distance, distances[nr_node_levels - 1]);
2335 WRITE_ONCE(sched_numa_node_levels, nr_node_levels);
2336
2337 rcu_assign_pointer(sched_domains_numa_distance, domain_distances);
2338
2339 sched_domains_numa_levels = 0;
2340
2341 masks = kzalloc(sizeof(void *) * nr_levels, GFP_KERNEL);
2342 if (!masks)
2343 goto free_distance;
2344
2345 for (i = 0; i < nr_levels; i++) {
2346 masks[i] = kzalloc(nr_node_ids * sizeof(void *), GFP_KERNEL);
2347 if (!masks[i]) {
2348 for (i = i - 1; i >= 0; i--) {
2349 if (!masks[i])
2350 continue;
2351 for_each_cpu_node_but(j, offline_node)
2352 kfree(masks[i][j]);
2353 kfree(masks[i]);
2354 }
2355 kfree(masks);
2356 goto free_distance;
2357 }
2358
2359 for_each_cpu_node_but(j, offline_node) {
2360 struct cpumask *mask = kzalloc(cpumask_size(), GFP_KERNEL);
2361 int k;
2362
2363 if (!mask) {
> 2364 for (i = i; i >= 0; i--) {
2365 if (!masks[i])
2366 continue;
2367 for_each_cpu_node_but(j, offline_node)
2368 kfree(masks[i][j]);
2369 kfree(masks[i]);
2370 }
2371 kfree(masks);
2372 goto free_distance;
2373 }
2374
2375 masks[i][j] = mask;
2376
2377 for_each_cpu_node_but(k, offline_node) {
2378 if (sched_debug() &&
2379 (arch_sched_node_distance(j, k) !=
2380 arch_sched_node_distance(k, j)))
2381 sched_numa_warn("Node-distance not symmetric");
2382
2383 if (arch_sched_node_distance(j, k) >
2384 sched_domains_numa_distance[i])
2385 continue;
2386
2387 cpumask_or(mask, mask, cpumask_of_node(k));
2388 }
2389 }
2390 }
2391 rcu_assign_pointer(sched_domains_numa_masks, masks);
2392
2393 for (i = 0; sched_domain_topology[i].mask; i++);
2394
2395 tl = kzalloc((i + nr_levels + 1) *
2396 sizeof(struct sched_domain_topology_level), GFP_KERNEL);
2397 if (!tl) {
2398 rcu_assign_pointer(sched_domains_numa_masks, NULL);
2399 for (i = nr_levels - 1; i >= 0; i--) {
2400 if (!masks[i])
2401 continue;
2402 for_each_cpu_node_but(j, offline_node)
2403 kfree(masks[i][j]);
2404 kfree(masks[i]);
2405 }
2406 kfree(masks);
2407 goto free_distance;
2408 }
2409
2410 for (i = 0; sched_domain_topology[i].mask; i++)
2411 tl[i] = sched_domain_topology[i];
2412
2413 tl[i++] = SDTL_INIT(sd_numa_mask, NULL, NODE);
2414
2415 for (j = 1; j < nr_levels; i++, j++) {
2416 tl[i] = SDTL_INIT(sd_numa_mask, cpu_numa_flags, NUMA);
2417 tl[i].numa_level = j;
2418 }
2419
2420 sched_domain_topology_saved = sched_domain_topology;
2421 sched_domain_topology = tl;
2422
2423 sched_domains_numa_levels = nr_levels;
2424
2425 init_numa_topology_type(offline_node);
2426 return;
2427
2428 free_distance:
2429 if (domain_distances != distances)
2430 kfree(domain_distances);
2431 }
2432
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-08-14 13:57 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-09 23:03 [PATCH] sched/topology: fix memory leaks in allocation failure paths monios114514
2026-08-14 13:56 ` kernel test robot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.