[PATCH] Replacement for Arm initrd memblock reserve and free inconsistency.

Russell King - ARM Linux linux at armlinux.org.uk
Thu Nov 10 09:46:45 PST 2016

On Wed, Nov 09, 2016 at 04:35:37PM +0000, william.helsby at stfc.ac.uk wrote:
> A boot time system crash was noticed with a segmentation fault just after the initrd image had been used to initialise the ramdisk.
> This occurred when the U-Boot loaded the ramdisk image from a FAT partition, but not when loaded by TFTPBOOT. This is not understood?
> However the problem was caused by free_initrd_mem freeing and "poisoning" memory that had been allocted to init/main.c to store the saved_command_line
> This patch reverses "ARM: 8167/1: extend the reserved memory for initrd to be page aligned" because it is safer to leave a partial head or tail page reserved (wasted) than to free a page which is partially still in use.
> If this is not acceptable (particularly if wanting large contiguous physical areas for DMA) then a better solution is required.
> This would extend the region reserved to page boundaries, if possible without overlapping other regions. My previous attempt to fix this coded this scheme, to grow the are reserved. 
> However, this  again is not safe if in growing the area it then overlaps a region that is in use.
> Note this path is against the 4.6 kernel, but as far as I can tell applies equally to 4.8.

Please wrap commit messages at or before column 72, the exception is
for lines with a URL.

> diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
> index 370581a..ff3e9c3 100644
> --- a/arch/arm/mm/init.c
> +++ b/arch/arm/mm/init.c
> @@ -770,12 +770,6 @@ static int keep_initrd;
> void free_initrd_mem(unsigned long start, unsigned long end)
> {
>         if (!keep_initrd) {
> -               if (start == initrd_start)
> -                       start = round_down(start, PAGE_SIZE);
> -               if (end == initrd_end)
> -                       end = round_up(end, PAGE_SIZE);
> -
> -               poison_init_mem((void *)start, PAGE_ALIGN(end) - start);

We're definitely not getting rid of the poisoning of the pages - the
poisoning there is to detect accesses to this memory which should not
be made.

The point of rounding up and down is to ensure that the partly-used
pages (which would have been previously reserved) are freed.

Probably a better fix is to round the start up/end down of the initrd
when reserving the memory region:

 arch/arm/mm/init.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 370581aeb871..ee8509e4329d 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -255,7 +255,11 @@ void __init arm_memblock_init(const struct machine_desc *mdesc)
 		phys_initrd_start = phys_initrd_size = 0;
 	if (phys_initrd_size) {
-		memblock_reserve(phys_initrd_start, phys_initrd_size);
+		phys_addr_t start, size;
+		start = round_down(phys_initrd_start, PAGE_SIZE);
+		end = round_up(phys_initrd_start + phys_initrd_size, PAGE_SIZE);
+		memblock_reserve(start, end - start);
 		/* Now convert initrd to virtual addresses */
 		initrd_start = __phys_to_virt(phys_initrd_start);

and this should ensure that memblock_alloc() doesn't try to allocate
memory overlapping the pages containing the initrd.

Intentionally using pages overlapping the initrd is a recipe for

RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.

More information about the linux-arm-kernel mailing list