From 57b3f8a5ab282f7d9fe6564a310e02675faeba89 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Mon, 9 Jan 2023 12:53:15 -0800 Subject: [PATCH] FROMLIST: mm/mmap: write-lock VMAs in vma_adjust vma_adjust modifies a VMA and possibly its neighbors. Write-lock them before making the modifications. Signed-off-by: Suren Baghdasaryan Link: https://lore.kernel.org/all/20230109205336.3665937-21-surenb@google.com/ [surenb: using older v1 of patchset due to __vma_adjust() being removed in 6.2-rc4] [surenb: minor fixes in next_next locking inside __vma_adjust] Bug: 161210518 Change-Id: I9ab2f88c82a7071fe2f1a14c51a2e6f1b6196681 Signed-off-by: Suren Baghdasaryan --- mm/mmap.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/mm/mmap.c b/mm/mmap.c index d2856590427c..704b655a55be 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -618,6 +618,12 @@ nomem: * The following helper function should be used when such adjustments * are necessary. The "insert" vma (if any) is to be inserted * before we drop the necessary locks. + * 'expand' vma is always locked before it's passed to __vma_adjust() + * from vma_merge() because vma should not change from the moment + * can_vma_merge_{before|after} decision is made. + * 'insert' vma is used only by __split_vma() and it's always a brand + * new vma which is not yet added into mm's vma tree, therefore no need + * to lock it. */ int __vma_adjust(struct vm_area_struct *vma, unsigned long start, unsigned long end, pgoff_t pgoff, struct vm_area_struct *insert, @@ -637,6 +643,10 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start, MA_STATE(mas, &mm->mm_mt, start, end - 1); struct vm_area_struct *exporter = NULL, *importer = NULL; + vma_start_write(vma); + if (next) + vma_start_write(next); + if (next && !insert) { if (end >= next->vm_end) { /* @@ -666,8 +676,11 @@ int __vma_adjust(struct vm_area_struct *vma, unsigned long start, * remove_next == 1 is case 1 or 7. */ remove_next = 1 + (end > next->vm_end); - if (remove_next == 2) + if (remove_next == 2) { next_next = find_vma(mm, next->vm_end); + if (next_next) + vma_start_write(next_next); + } VM_WARN_ON(remove_next == 2 && end != next_next->vm_end);