On parisc the kernel fails to start the init process because in shift_arg_pages() in fs/exec.c, move_page_tables() is called to e.g. move pages from start addr 0xffeff000 to the new start addr 0xf9ccb000 with a length of 0x1000 bytes, but move_page_tables() instead returns that it apparently moved 0x57000 bytes. Since the number of bytes is different than the number of bytes which should have been moved, shift_arg_pages() aborts with -ENOMEM. Debugging shows that commit c49dd34018026 ("mm: speedup mremap on 1GB or larger regions") is the culprit. In this commit, the extent calculation was tried to be optimized, but got it wrong for this case. The patch below reverts to the previous way to calculate the extent and thus fixes the boot problem. Fixes: c49dd34018026 ("mm: speedup mremap on 1GB or larger regions") Signed-off-by: Helge Deller <deller@xxxxxx> Cc: Kalesh Singh <kaleshsingh@xxxxxxxxxx> Cc: "Kirill A. Shutemov" <kirill.shutemov@xxxxxxxxxxxxxxx> Cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- diff --git a/mm/mremap.c b/mm/mremap.c index c5590afe7165..f554320281cc 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -358,7 +358,9 @@ static unsigned long get_extent(enum pgt_entry entry, unsigned long old_addr, next = (old_addr + size) & mask; /* even if next overflowed, extent below will be ok */ - extent = (next > old_end) ? old_end - old_addr : next - old_addr; + extent = next - old_addr; + if (extent > old_end - old_addr) + extent = old_end - old_addr; next = (new_addr + size) & mask; if (extent > next - new_addr) extent = next - new_addr;