All of lore.kernel.org
 help / color / mirror / Atom feed
* [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.