Commit 77e02cf5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

memblock: introduce saner 'memblock_free_ptr()' interface

The boot-time allocation interface for memblock is a mess, with
'memblock_alloc()' returning a virtual pointer, but then you are
supposed to free it with 'memblock_free()' that takes a _physical_
address.

Not only is that all kinds of strange and illogical, but it actually
causes bugs, when people then use it like a normal allocation function,
and it fails spectacularly on a NULL pointer:

   https://lore.kernel.org/all/20210912140820.GD25450@xsang-OptiPlex-9020/

or just random memory corruption if the debug checks don't catch it:

   https://lore.kernel.org/all/61ab2d0c-3313-aaab-514c-e15b7aa054a0@suse.cz/



I really don't want to apply patches that treat the symptoms, when the
fundamental cause is this horribly confusing interface.

I started out looking at just automating a sane replacement sequence,
but because of this mix or virtual and physical addresses, and because
people have used the "__pa()" macro that can take either a regular
kernel pointer, or just the raw "unsigned long" address, it's all quite
messy.

So this just introduces a new saner interface for freeing a virtual
address that was allocated using 'memblock_alloc()', and that was kept
as a regular kernel pointer.  And then it converts a couple of users
that are obvious and easy to test, including the 'xbc_nodes' case in
lib/bootconfig.c that caused problems.

Reported-by: default avatarkernel test robot <oliver.sang@intel.com>
Fixes: 40caa127 ("init: bootconfig: Remove all bootconfig data when the init memory is removed")
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 6a4746ba
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -135,7 +135,7 @@ static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size, size_t align)

static void __init pcpu_fc_free(void *ptr, size_t size)
{
	memblock_free(__pa(ptr), size);
	memblock_free_ptr(ptr, size);
}

static int __init pcpu_cpu_distance(unsigned int from, unsigned int to)
+2 −4
Original line number Diff line number Diff line
@@ -49,8 +49,7 @@ static void __init kasan_populate_pmd(pmd_t *pmd, unsigned long addr,
			p = early_alloc(PMD_SIZE, nid, false);
			if (p && pmd_set_huge(pmd, __pa(p), PAGE_KERNEL))
				return;
			else if (p)
				memblock_free(__pa(p), PMD_SIZE);
			memblock_free_ptr(p, PMD_SIZE);
		}

		p = early_alloc(PAGE_SIZE, nid, true);
@@ -86,8 +85,7 @@ static void __init kasan_populate_pud(pud_t *pud, unsigned long addr,
			p = early_alloc(PUD_SIZE, nid, false);
			if (p && pud_set_huge(pud, __pa(p), PAGE_KERNEL))
				return;
			else if (p)
				memblock_free(__pa(p), PUD_SIZE);
			memblock_free_ptr(p, PUD_SIZE);
		}

		p = early_alloc(PAGE_SIZE, nid, true);
+1 −1
Original line number Diff line number Diff line
@@ -355,7 +355,7 @@ void __init numa_reset_distance(void)

	/* numa_distance could be 1LU marking allocation failure, test cnt */
	if (numa_distance_cnt)
		memblock_free(__pa(numa_distance), size);
		memblock_free_ptr(numa_distance, size);
	numa_distance_cnt = 0;
	numa_distance = NULL;	/* enable table creation */
}
+1 −2
Original line number Diff line number Diff line
@@ -517,8 +517,7 @@ void __init numa_emulation(struct numa_meminfo *numa_meminfo, int numa_dist_cnt)
	}

	/* free the copied physical distance table */
	if (phys_dist)
		memblock_free(__pa(phys_dist), phys_size);
	memblock_free_ptr(phys_dist, phys_size);
	return;

no_emu:
+1 −1
Original line number Diff line number Diff line
@@ -264,7 +264,7 @@ void __init numa_free_distance(void)
	size = numa_distance_cnt * numa_distance_cnt *
		sizeof(numa_distance[0]);

	memblock_free(__pa(numa_distance), size);
	memblock_free_ptr(numa_distance, size);
	numa_distance_cnt = 0;
	numa_distance = NULL;
}
Loading