[PATCH] mm: fix extend calculation for move_page_tables()

From: Helge Deller
Date: Tue Dec 29 2020 - 12:47:18 EST


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;