Skip to contentSkip to conversation

mm: protect free_pgtables with mmap_lock write lock in exit_mmap

PATCH Superseded Suren Baghdasaryan 3 participants 9 messages Nov 24, 2021 – Dec 7, 2021

Subsystems (3)

v2 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/2 mm: protect free_pgtables with mmap_lock write lock in exit_mmap

oom-reaper and process_mrelease system call should protect against races with exit_mmap which can destroy page tables while they walk the VMA tree. oom-reaper protects from that race by setting MMF_OOM_VICTIM and by relying on exit_mmap to set MMF_OOM_SKIP before taking and releasing mmap_write_lock. process_mrelease has to elevate mm->mm_users to prevent such race. Both oom-reaper and process_mrelease hold mmap_read_lock when walking the VMA tree. The locking rules and mechanisms could be simpler if exit_mmap takes mmap_write_lock while executing destructive operations such as free_pgtables.
Change exit_mmap to hold the mmap_write_lock when calling free_pgtables. Operations like unmap_vmas() and unlock_range() are not destructive and could run under mmap_read_lock but for simplicity we take one mmap_write_lock during almost the entire operation. Note also that because oom-reaper checks VM_LOCKED flag, unlock_range() should not be allowed to race with it.
In most cases this lock should be uncontended. Previously, Kirill reported ~4% regression caused by a similar change [1]. We reran the same test and although the individual results are quite noisy, the percentiles show lower regression with 1.6% being the worst case [2]. The change allows oom-reaper and process_mrelease to execute safely under mmap_read_lock without worries that exit_mmap might destroy page tables from under them.

[1] https://lore.kernel.org/all/[email protected]/
[2] https://lore.kernel.org/all/CAJuCfpGC9-c9P40x7oy=jy5SphMcd0o0G_6U1-+JAziGKG6dGA@mail.gmail.com/

---
changes in v2
- Moved mmap_write_unlock to cover remove_vma loop as well, per Matthew Wilcox

 mm/mmap.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
mm/mmap.c +8 -8
index bfb0ea164a90..f4e09d390a07 100644
@@ -3142,25 +3142,27 @@ void exit_mmap(struct mm_struct *mm)
 		 * to mmu_notifier_release(mm) ensures mmu notifier callbacks in
 		 * __oom_reap_task_mm() will not block.
 		 *
-		 * This needs to be done before calling munlock_vma_pages_all(),
+		 * This needs to be done before calling unlock_range(),
 		 * which clears VM_LOCKED, otherwise the oom reaper cannot
 		 * reliably test it.
 		 */
 		(void)__oom_reap_task_mm(mm);
 
 		set_bit(MMF_OOM_SKIP, &mm->flags);
-		mmap_write_lock(mm);
-		mmap_write_unlock(mm);
 	}
 
+	mmap_write_lock(mm);
 	if (mm->locked_vm)
 		unlock_range(mm->mmap, ULONG_MAX);
 
 	arch_exit_mmap(mm);
 
 	vma = mm->mmap;
-	if (!vma)	/* Can happen if dup_mmap() received an OOM */
+	if (!vma) {
+		/* Can happen if dup_mmap() received an OOM */
+		mmap_write_unlock(mm);
 		return;
+	}
 
 	lru_add_drain();
 	flush_cache_mm(mm);
@@ -3171,16 +3173,14 @@ void exit_mmap(struct mm_struct *mm)
 	free_pgtables(&tlb, vma, FIRST_USER_ADDRESS, USER_PGTABLES_CEILING);
 	tlb_finish_mmu(&tlb);
 
-	/*
-	 * Walk the list again, actually closing and freeing it,
-	 * with preemption enabled, without holding any MM locks.
-	 */
+	/* Walk the list again, actually closing and freeing it. */
 	while (vma) {
 		if (vma->vm_flags & VM_ACCOUNT)
 			nr_accounted += vma_pages(vma);
 		vma = remove_vma(vma);
 		cond_resched();
 	}
+	mmap_write_unlock(mm);
 	vm_unacct_memory(nr_accounted);
 }
 
Signature · 1 line
2.34.0.rc2.393.gf8c9666880-goog
#1 lore raw

PATCH v2 2/2 mm/oom_kill: allow process_mrelease to run under mmap_lock protection

With exit_mmap holding mmap_write_lock during free_pgtables call, process_mrelease does not need to elevate mm->mm_users in order to prevent exit_mmap from destrying pagetables while __oom_reap_task_mm is walking the VMA tree. The change prevents process_mrelease from calling the last mmput, which can lead to waiting for IO completion in exit_aio.

Fixes 337546e83fc7 ("mm/oom_kill.c: prevent a race between process_mrelease and exit_mmap")
---
 mm/oom_kill.c | 27 +++++++++++++++------------
 1 file changed, 15 insertions(+), 12 deletions(-)
mm/oom_kill.c +15 -12
index 1ddabefcfb5a..67780386f478 100644
@@ -1169,15 +1169,15 @@ SYSCALL_DEFINE2(process_mrelease, int, pidfd, unsigned int, flags)
 		goto put_task;
 	}
 
-	if (mmget_not_zero(p->mm)) {
-		mm = p->mm;
-		if (task_will_free_mem(p))
-			reap = true;
-		else {
-			/* Error only if the work has not been done already */
-			if (!test_bit(MMF_OOM_SKIP, &mm->flags))
-				ret = -EINVAL;
-		}
+	mm = p->mm;
+	mmgrab(mm);
+
+	if (task_will_free_mem(p))
+		reap = true;
+	else {
+		/* Error only if the work has not been done already */
+		if (!test_bit(MMF_OOM_SKIP, &mm->flags))
+			ret = -EINVAL;
 	}
 	task_unlock(p);
 
@@ -1188,13 +1188,16 @@ SYSCALL_DEFINE2(process_mrelease, int, pidfd, unsigned int, flags)
 		ret = -EINTR;
 		goto drop_mm;
 	}
-	if (!__oom_reap_task_mm(mm))
+	/*
+	 * Check MMF_OOM_SKIP again under mmap_read_lock protection to ensure
+	 * possible change in exit_mmap is seen
+	 */
+	if (!test_bit(MMF_OOM_SKIP, &mm->flags) && !__oom_reap_task_mm(mm))
 		ret = -EAGAIN;
 	mmap_read_unlock(mm);
 
 drop_mm:
-	if (mm)
-		mmput(mm);
+	mmdrop(mm);
 put_task:
 	put_task_struct(task);
 	return ret;
Signature · 1 line
2.34.0.rc2.393.gf8c9666880-goog
maintainer
#2 lore raw
In reply to Suren Baghdasaryan
Quoted 41 lines · Suren Baghdasaryan

oom-reaper and process_mrelease system call should protect against races with exit_mmap which can destroy page tables while they walk the VMA tree. oom-reaper protects from that race by setting MMF_OOM_VICTIM and by relying on exit_mmap to set MMF_OOM_SKIP before taking and releasing mmap_write_lock. process_mrelease has to elevate mm->mm_users to prevent such race. Both oom-reaper and process_mrelease hold mmap_read_lock when walking the VMA tree. The locking rules and mechanisms could be simpler if exit_mmap takes mmap_write_lock while executing destructive operations such as free_pgtables.
Change exit_mmap to hold the mmap_write_lock when calling free_pgtables. Operations like unmap_vmas() and unlock_range() are not destructive and could run under mmap_read_lock but for simplicity we take one mmap_write_lock during almost the entire operation. Note also that because oom-reaper checks VM_LOCKED flag, unlock_range() should not be allowed to race with it.
In most cases this lock should be uncontended. Previously, Kirill reported ~4% regression caused by a similar change [1]. We reran the same test and although the individual results are quite noisy, the percentiles show lower regression with 1.6% being the worst case [2]. The change allows oom-reaper and process_mrelease to execute safely under mmap_read_lock without worries that exit_mmap might destroy page tables from under them.

[1] https://lore.kernel.org/all/[email protected]/
[2] https://lore.kernel.org/all/CAJuCfpGC9-c9P40x7oy=jy5SphMcd0o0G_6U1-+JAziGKG6dGA@mail.gmail.com/

---
changes in v2
- Moved mmap_write_unlock to cover remove_vma loop as well, per Matthew Wilcox

 mm/mmap.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
mm/mmap.c +0 -0
index bfb0ea164a90..f4e09d390a07 100644
@@ -3142,25 +3142,27 @@ void exit_mmap(struct mm_struct *mm)
 		 * to mmu_notifier_release(mm) ensures mmu notifier callbacks in

mm/mmap.c void exit_mmap(struct mm_struct *mm) · line 3151

Quoted 10 lines
mm/mmap.c +1 -1
 		 * __oom_reap_task_mm() will not block.
 		 *
-		 * This needs to be done before calling munlock_vma_pages_all(),
+		 * This needs to be done before calling unlock_range(),
 		 * which clears VM_LOCKED, otherwise the oom reaper cannot
 		 * reliably test it.
 		 */
 		(void)__oom_reap_task_mm(mm);
 
 		set_bit(MMF_OOM_SKIP, &mm->flags);

Why do you keep this in place?

Other than that looks OK to me. Maybe we want to add an explicit note that vm_ops::close cannot take mmap_sem in any form. The changelog should also mention that you have considered remove_vma and its previous no MM locking assumption. You can argue that fput is async and close callback shouldn't really need mmap_sem.

Signature · 2 lines
Michal Hocko
SUSE Labs
#3 lore raw
Quoted 52 lines · Michal Hocko
Quoted 50 lines · Suren Baghdasaryan

oom-reaper and process_mrelease system call should protect against races with exit_mmap which can destroy page tables while they walk the VMA tree. oom-reaper protects from that race by setting MMF_OOM_VICTIM and by relying on exit_mmap to set MMF_OOM_SKIP before taking and releasing mmap_write_lock. process_mrelease has to elevate mm->mm_users to prevent such race. Both oom-reaper and process_mrelease hold mmap_read_lock when walking the VMA tree. The locking rules and mechanisms could be simpler if exit_mmap takes mmap_write_lock while executing destructive operations such as free_pgtables.
Change exit_mmap to hold the mmap_write_lock when calling free_pgtables. Operations like unmap_vmas() and unlock_range() are not destructive and could run under mmap_read_lock but for simplicity we take one mmap_write_lock during almost the entire operation. Note also that because oom-reaper checks VM_LOCKED flag, unlock_range() should not be allowed to race with it.
In most cases this lock should be uncontended. Previously, Kirill reported ~4% regression caused by a similar change [1]. We reran the same test and although the individual results are quite noisy, the percentiles show lower regression with 1.6% being the worst case [2]. The change allows oom-reaper and process_mrelease to execute safely under mmap_read_lock without worries that exit_mmap might destroy page tables from under them.

[1] https://lore.kernel.org/all/[email protected]/
[2] https://lore.kernel.org/all/CAJuCfpGC9-c9P40x7oy=jy5SphMcd0o0G_6U1-+JAziGKG6dGA@mail.gmail.com/

---
changes in v2
- Moved mmap_write_unlock to cover remove_vma loop as well, per Matthew Wilcox

 mm/mmap.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
mm/mmap.c +1 -1
index bfb0ea164a90..f4e09d390a07 100644
@@ -3142,25 +3142,27 @@ void exit_mmap(struct mm_struct *mm)
               * to mmu_notifier_release(mm) ensures mmu notifier callbacks in
               * __oom_reap_task_mm() will not block.
               *
-              * This needs to be done before calling munlock_vma_pages_all(),
+              * This needs to be done before calling unlock_range(),
               * which clears VM_LOCKED, otherwise the oom reaper cannot
               * reliably test it.
               */
              (void)__oom_reap_task_mm(mm);
 
Quoted 3 lines

mm/mmap.c void exit_mmap(struct mm_struct *mm) · line 3151

Quoted 1 line
mm/mmap.c +0 -0
              set_bit(MMF_OOM_SKIP, &mm->flags);

Why do you keep this in place?

Sorry for the delay, I was out last week.
I missed your comment about removing MMF_OOM_SKIP at
https://lore.kernel.org/all/YYrO%[email protected]
I'll look into removing it in a separate patch, which I think would be cleaner.

Quoted 6 lines

Other than that looks OK to me. Maybe we want to add an explicit note that vm_ops::close cannot take mmap_sem in any form. The changelog should also mention that you have considered remove_vma and its previous no MM locking assumption. You can argue that fput is async and close callback shouldn't really need mmap_sem.

Should I post another version of this patch with the patch description clarifying these points and additional comments as you suggested?

Quoted 3 lines

--
Michal Hocko
SUSE Labs

#4 lore raw
Quoted 8 lines · Suren Baghdasaryan
Quoted 5 lines

Other than that looks OK to me. Maybe we want to add an explicit note that vm_ops::close cannot take mmap_sem in any form. The changelog should also mention that you have considered remove_vma and its previous no MM locking assumption. You can argue that fput is async and close callback shouldn't really need mmap_sem.

Should I post another version of this patch with the patch description clarifying these points and additional comments as you suggested?

fyi, vm_ops->close() is already called with the mmap_sem held for write in __split_vma(). If that needs to be documented, it's a separate patch because it's absolutely not a consequence of this patch.

maintainer
#5 lore raw
Quoted 7 lines · Matthew Wilcox
Quoted 6 lines · Suren Baghdasaryan
Quoted 5 lines

Other than that looks OK to me. Maybe we want to add an explicit note that vm_ops::close cannot take mmap_sem in any form. The changelog should also mention that you have considered remove_vma and its previous no MM locking assumption. You can argue that fput is async and close callback shouldn't really need mmap_sem.

Quoted 6 lines
Quoted 2 lines

Should I post another version of this patch with the patch description clarifying these points and additional comments as you suggested?

fyi, vm_ops->close() is already called with the mmap_sem held for write in __split_vma(). If that needs to be documented, it's a separate patch because it's absolutely not a consequence of this patch.

Agreed! We definitely want to document that.

Signature · 2 lines
Michal Hocko
SUSE Labs
maintainer
#6 lore raw
In reply to Suren Baghdasaryan
Quoted 53 lines · Suren Baghdasaryan
Quoted 52 lines · Michal Hocko
Quoted 50 lines · Suren Baghdasaryan

oom-reaper and process_mrelease system call should protect against races with exit_mmap which can destroy page tables while they walk the VMA tree. oom-reaper protects from that race by setting MMF_OOM_VICTIM and by relying on exit_mmap to set MMF_OOM_SKIP before taking and releasing mmap_write_lock. process_mrelease has to elevate mm->mm_users to prevent such race. Both oom-reaper and process_mrelease hold mmap_read_lock when walking the VMA tree. The locking rules and mechanisms could be simpler if exit_mmap takes mmap_write_lock while executing destructive operations such as free_pgtables.
Change exit_mmap to hold the mmap_write_lock when calling free_pgtables. Operations like unmap_vmas() and unlock_range() are not destructive and could run under mmap_read_lock but for simplicity we take one mmap_write_lock during almost the entire operation. Note also that because oom-reaper checks VM_LOCKED flag, unlock_range() should not be allowed to race with it.
In most cases this lock should be uncontended. Previously, Kirill reported ~4% regression caused by a similar change [1]. We reran the same test and although the individual results are quite noisy, the percentiles show lower regression with 1.6% being the worst case [2]. The change allows oom-reaper and process_mrelease to execute safely under mmap_read_lock without worries that exit_mmap might destroy page tables from under them.

[1] https://lore.kernel.org/all/[email protected]/
[2] https://lore.kernel.org/all/CAJuCfpGC9-c9P40x7oy=jy5SphMcd0o0G_6U1-+JAziGKG6dGA@mail.gmail.com/

---
changes in v2
- Moved mmap_write_unlock to cover remove_vma loop as well, per Matthew Wilcox

 mm/mmap.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
mm/mmap.c +1 -1
index bfb0ea164a90..f4e09d390a07 100644
@@ -3142,25 +3142,27 @@ void exit_mmap(struct mm_struct *mm)
               * to mmu_notifier_release(mm) ensures mmu notifier callbacks in
               * __oom_reap_task_mm() will not block.
               *
-              * This needs to be done before calling munlock_vma_pages_all(),
+              * This needs to be done before calling unlock_range(),
               * which clears VM_LOCKED, otherwise the oom reaper cannot
               * reliably test it.
               */
              (void)__oom_reap_task_mm(mm);
 
Quoted 8 lines
Quoted 3 lines

mm/mmap.c void exit_mmap(struct mm_struct *mm) · line 3151

Quoted 1 line
mm/mmap.c +0 -0
              set_bit(MMF_OOM_SKIP, &mm->flags);

Why do you keep this in place?

Sorry for the delay, I was out last week.
I missed your comment about removing MMF_OOM_SKIP at
https://lore.kernel.org/all/YYrO%[email protected]
I'll look into removing it in a separate patch, which I think would be cleaner.

The point of this code was to sync up the oom_repaer and exit_mmap. Now that your patch uses proper locking for that to happen then MMF_OOM_SKIP is not really necessary. IIRC all you need to guarantee is that the vma tree is empty when exit_mmap does all its work - i.e set mm->mmap to NULL. You can do that after remove_vma loop but it would be equally safe at any time after vma = mm->mmap as the loop relies on the vma chain. Doing that after would be slightly nicer if you ask me.

Quoted 8 lines
Quoted 5 lines

Other than that looks OK to me. Maybe we want to add an explicit note that vm_ops::close cannot take mmap_sem in any form. The changelog should also mention that you have considered remove_vma and its previous no MM locking assumption. You can argue that fput is async and close callback shouldn't really need mmap_sem.

Should I post another version of this patch with the patch description clarifying these points and additional comments as you suggested?

Yes please.

Signature · 2 lines
Michal Hocko
SUSE Labs
#7 lore raw
Quoted 64 lines · Michal Hocko
Quoted 53 lines · Suren Baghdasaryan
Quoted 52 lines · Michal Hocko
Quoted 50 lines · Suren Baghdasaryan

oom-reaper and process_mrelease system call should protect against races with exit_mmap which can destroy page tables while they walk the VMA tree. oom-reaper protects from that race by setting MMF_OOM_VICTIM and by relying on exit_mmap to set MMF_OOM_SKIP before taking and releasing mmap_write_lock. process_mrelease has to elevate mm->mm_users to prevent such race. Both oom-reaper and process_mrelease hold mmap_read_lock when walking the VMA tree. The locking rules and mechanisms could be simpler if exit_mmap takes mmap_write_lock while executing destructive operations such as free_pgtables.
Change exit_mmap to hold the mmap_write_lock when calling free_pgtables. Operations like unmap_vmas() and unlock_range() are not destructive and could run under mmap_read_lock but for simplicity we take one mmap_write_lock during almost the entire operation. Note also that because oom-reaper checks VM_LOCKED flag, unlock_range() should not be allowed to race with it.
In most cases this lock should be uncontended. Previously, Kirill reported ~4% regression caused by a similar change [1]. We reran the same test and although the individual results are quite noisy, the percentiles show lower regression with 1.6% being the worst case [2]. The change allows oom-reaper and process_mrelease to execute safely under mmap_read_lock without worries that exit_mmap might destroy page tables from under them.

[1] https://lore.kernel.org/all/[email protected]/
[2] https://lore.kernel.org/all/CAJuCfpGC9-c9P40x7oy=jy5SphMcd0o0G_6U1-+JAziGKG6dGA@mail.gmail.com/

---
changes in v2
- Moved mmap_write_unlock to cover remove_vma loop as well, per Matthew Wilcox

 mm/mmap.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
mm/mmap.c +1 -1
index bfb0ea164a90..f4e09d390a07 100644
@@ -3142,25 +3142,27 @@ void exit_mmap(struct mm_struct *mm)
               * to mmu_notifier_release(mm) ensures mmu notifier callbacks in
               * __oom_reap_task_mm() will not block.
               *
-              * This needs to be done before calling munlock_vma_pages_all(),
+              * This needs to be done before calling unlock_range(),
               * which clears VM_LOCKED, otherwise the oom reaper cannot
               * reliably test it.
               */
              (void)__oom_reap_task_mm(mm);
 
Quoted 8 lines
Quoted 3 lines

mm/mmap.c void exit_mmap(struct mm_struct *mm) · line 3151

Quoted 1 line
mm/mmap.c +0 -0
              set_bit(MMF_OOM_SKIP, &mm->flags);

Why do you keep this in place?

Sorry for the delay, I was out last week.
I missed your comment about removing MMF_OOM_SKIP at
https://lore.kernel.org/all/YYrO%[email protected]
I'll look into removing it in a separate patch, which I think would be cleaner.

Quoted 7 lines

The point of this code was to sync up the oom_repaer and exit_mmap. Now that your patch uses proper locking for that to happen then MMF_OOM_SKIP is not really necessary. IIRC all you need to guarantee is that the vma tree is empty when exit_mmap does all its work - i.e set mm->mmap to NULL. You can do that after remove_vma loop but it would be equally safe at any time after vma = mm->mmap as the loop relies on the vma chain. Doing that after would be slightly nicer if you ask me.

Will do. But if you don't mind I'll post the removal of MMF_OOM_SKIP as a separate patch. This patchset has already been extensively tested and it will be easier for me to test MMF_OOM_SKIP removal separately.

Quoted 11 lines
Quoted 9 lines
Quoted 6 lines

Other than that looks OK to me. Maybe we want to add an explicit note that vm_ops::close cannot take mmap_sem in any form. The changelog should also mention that you have considered remove_vma and its previous no MM locking assumption. You can argue that fput is async and close callback shouldn't really need mmap_sem.

Should I post another version of this patch with the patch description clarifying these points and additional comments as you suggested?

Yes please.

Will re-post. So, to clarify, we want:
- Patch description to include explanation that remove_vma is now being called under MM lock but this should not be a problem because fput and vm_ops->close do not and should not take mmap_sem.
- Add a comment for vm_ops->close that the callback should not take mmap_sem, with explanation that __split_vma and exit_mmap use this callback with the mmap_sem write lock taken.
Is that correct?

Quoted 4 lines

--
Michal Hocko
SUSE Labs

#8 lore raw
Quoted 90 lines · Suren Baghdasaryan
Quoted 64 lines · Michal Hocko
Quoted 53 lines · Suren Baghdasaryan
Quoted 52 lines · Michal Hocko
Quoted 50 lines · Suren Baghdasaryan

oom-reaper and process_mrelease system call should protect against races with exit_mmap which can destroy page tables while they walk the VMA tree. oom-reaper protects from that race by setting MMF_OOM_VICTIM and by relying on exit_mmap to set MMF_OOM_SKIP before taking and releasing mmap_write_lock. process_mrelease has to elevate mm->mm_users to prevent such race. Both oom-reaper and process_mrelease hold mmap_read_lock when walking the VMA tree. The locking rules and mechanisms could be simpler if exit_mmap takes mmap_write_lock while executing destructive operations such as free_pgtables.
Change exit_mmap to hold the mmap_write_lock when calling free_pgtables. Operations like unmap_vmas() and unlock_range() are not destructive and could run under mmap_read_lock but for simplicity we take one mmap_write_lock during almost the entire operation. Note also that because oom-reaper checks VM_LOCKED flag, unlock_range() should not be allowed to race with it.
In most cases this lock should be uncontended. Previously, Kirill reported ~4% regression caused by a similar change [1]. We reran the same test and although the individual results are quite noisy, the percentiles show lower regression with 1.6% being the worst case [2]. The change allows oom-reaper and process_mrelease to execute safely under mmap_read_lock without worries that exit_mmap might destroy page tables from under them.

[1] https://lore.kernel.org/all/[email protected]/
[2] https://lore.kernel.org/all/CAJuCfpGC9-c9P40x7oy=jy5SphMcd0o0G_6U1-+JAziGKG6dGA@mail.gmail.com/

---
changes in v2
- Moved mmap_write_unlock to cover remove_vma loop as well, per Matthew Wilcox

 mm/mmap.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
mm/mmap.c +1 -1
index bfb0ea164a90..f4e09d390a07 100644
@@ -3142,25 +3142,27 @@ void exit_mmap(struct mm_struct *mm)
               * to mmu_notifier_release(mm) ensures mmu notifier callbacks in
               * __oom_reap_task_mm() will not block.
               *
-              * This needs to be done before calling munlock_vma_pages_all(),
+              * This needs to be done before calling unlock_range(),
               * which clears VM_LOCKED, otherwise the oom reaper cannot
               * reliably test it.
               */
              (void)__oom_reap_task_mm(mm);
 
Quoted 8 lines
Quoted 3 lines

mm/mmap.c void exit_mmap(struct mm_struct *mm) · line 3151

Quoted 1 line
mm/mmap.c +0 -0
              set_bit(MMF_OOM_SKIP, &mm->flags);

Why do you keep this in place?

Sorry for the delay, I was out last week.
I missed your comment about removing MMF_OOM_SKIP at
https://lore.kernel.org/all/YYrO%[email protected]
I'll look into removing it in a separate patch, which I think would be cleaner.

Quoted 7 lines

The point of this code was to sync up the oom_repaer and exit_mmap. Now that your patch uses proper locking for that to happen then MMF_OOM_SKIP is not really necessary. IIRC all you need to guarantee is that the vma tree is empty when exit_mmap does all its work - i.e set mm->mmap to NULL. You can do that after remove_vma loop but it would be equally safe at any time after vma = mm->mmap as the loop relies on the vma chain. Doing that after would be slightly nicer if you ask me.

Will do. But if you don't mind I'll post the removal of MMF_OOM_SKIP as a separate patch. This patchset has already been extensively tested and it will be easier for me to test MMF_OOM_SKIP removal separately.

Quoted 11 lines
Quoted 9 lines
Quoted 6 lines

Other than that looks OK to me. Maybe we want to add an explicit note that vm_ops::close cannot take mmap_sem in any form. The changelog should also mention that you have considered remove_vma and its previous no MM locking assumption. You can argue that fput is async and close callback shouldn't really need mmap_sem.

Should I post another version of this patch with the patch description clarifying these points and additional comments as you suggested?

Yes please.

Quoted 8 lines

Will re-post. So, to clarify, we want:
- Patch description to include explanation that remove_vma is now being called under MM lock but this should not be a problem because fput and vm_ops->close do not and should not take mmap_sem.
- Add a comment for vm_ops->close that the callback should not take mmap_sem, with explanation that __split_vma and exit_mmap use this callback with the mmap_sem write lock taken.
Is that correct?

Assuming my understanding was correct, posted v3 at
https://lore.kernel.org/all/[email protected]/

Quoted 5 lines
Quoted 5 lines

--
Michal Hocko
SUSE Labs