No upstream commit exists for this patch.
The following assertion is firing on 5.10 to 6.1 stable kernels after backport of upstream commit 081056dc00a2 ("mm/hugetlb: unshare page tables during VMA split, not before"):
WARNING: CPU: 0 PID: 11489 at include/linux/fs.h:503 i_mmap_assert_write_locked include/linux/fs.h:503 [inline] WARNING: CPU: 0 PID: 11489 at include/linux/fs.h:503 hugetlb_split+0x267/0x300 mm/hugetlb.c:4917 Modules linked in: CPU: 0 PID: 11489 Comm: syz-executor.4 Not tainted 6.1.142-syzkaller-00296-gfd0df5221577 #0 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 RIP: 0010:i_mmap_assert_write_locked include/linux/fs.h:503 [inline] RIP: 0010:hugetlb_split+0x267/0x300 mm/hugetlb.c:4917 Call Trace: <TASK> __vma_adjust+0xd73/0x1c10 mm/mmap.c:736 vma_adjust include/linux/mm.h:2745 [inline] __split_vma+0x459/0x540 mm/mmap.c:2385 do_mas_align_munmap+0x5f2/0xf10 mm/mmap.c:2497 do_mas_munmap+0x26c/0x2c0 mm/mmap.c:2646 __mmap_region mm/mmap.c:2694 [inline] mmap_region+0x19f/0x1770 mm/mmap.c:2912 do_mmap+0x84b/0xf20 mm/mmap.c:1432 vm_mmap_pgoff+0x1af/0x280 mm/util.c:520 ksys_mmap_pgoff+0x41f/0x5a0 mm/mmap.c:1478 do_syscall_x64 arch/x86/entry/common.c:51 [inline] do_syscall_64+0x35/0x80 arch/x86/entry/common.c:81 entry_SYSCALL_64_after_hwframe+0x6e/0xd8 RIP: 0033:0x46a269 </TASK>
Those branches lack commit ccf1d78d8b86 ("mm/mmap: move vma_prepare before vma_adjust_trans_huge") so the needed locks are taken just after the newly added hugetlb_split().
Adjust the position of vma_adjust_trans_huge() blocks with the lock-taking code.
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
Fixes: 081056dc00a2 ("mm/hugetlb: unshare page tables during VMA split, not before") Signed-off-by: Fedor Pchelkin pchelkin@ispras.ru ---
Tested with testcases/kernel/mem/hugetlb/hugemmap suite provided by LTP.
For the report see: https://lore.kernel.org/stable/CAG48ez3LqUwXxhRY56tqQCpfGJsJ-GeXFG9FCcTZEBo2...
mm/mmap.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/mm/mmap.c b/mm/mmap.c index 0f303dc8425a..941880ed62d7 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -543,8 +543,6 @@ inline int vma_expand(struct ma_state *mas, struct vm_area_struct *vma, if (mas_preallocate(mas, vma, GFP_KERNEL)) goto nomem;
- vma_adjust_trans_huge(vma, start, end, 0); - if (file) { mapping = file->f_mapping; root = &mapping->i_mmap; @@ -562,6 +560,8 @@ inline int vma_expand(struct ma_state *mas, struct vm_area_struct *vma, vma_interval_tree_remove(vma, root); }
+ vma_adjust_trans_huge(vma, start, end, 0); + vma->vm_start = start; vma->vm_end = end; vma->vm_pgoff = pgoff; @@ -727,15 +727,6 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start, return -ENOMEM; }
- /* - * Get rid of huge pages and shared page tables straddling the split - * boundary. - */ - vma_adjust_trans_huge(orig_vma, start, end, adjust_next); - if (is_vm_hugetlb_page(orig_vma)) { - hugetlb_split(orig_vma, start); - hugetlb_split(orig_vma, end); - } if (file) { mapping = file->f_mapping; root = &mapping->i_mmap; @@ -775,6 +766,16 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start, vma_interval_tree_remove(next, root); }
+ /* + * Get rid of huge pages and shared page tables straddling the split + * boundary. + */ + vma_adjust_trans_huge(orig_vma, start, end, adjust_next); + if (is_vm_hugetlb_page(orig_vma)) { + hugetlb_split(orig_vma, start); + hugetlb_split(orig_vma, end); + } + if (start != vma->vm_start) { if ((vma->vm_start < start) && (!insert || (insert->vm_end != start))) {
linux-stable-mirror@lists.linaro.org