[Devel] [PATCH hci-8.1 2/8] oracle/mm: hold the source mmap write lock when copying PTEs
Konstantin Khorenko
khorenko at virtuozzo.com
Wed Oct 14 20:11:05 MSK 2026
From: Anthony Yznaga <anthony.yznaga at oracle.com>
The copy_p*_range() routines assume the mmap write lock is held
for both the source and destination and therefore there will be
no unexpected THP transitions while PTEs are copied (for example,
due to khugepaged). The write lock is already held on the destination
mm, but until now only the read lock was held on the source.
Orabug: 38029049
Signed-off-by: Anthony Yznaga <anthony.yznaga at oracle.com>
Reviewed-by: Harry Yoo <harry.yoo at oracle.com>
(cherry picked from commit 285a140316fa44f0cdc6608c109ba525e52d6c3f)
Taken from Oracle linux-uek branch uek8/u2. Applied cleanly; the only
change is a trailing space dropped from the new comment in exec_mmap().
Fixes: 9e6d16a6c0a1 ("oracle/mm: introduce VM_EXEC_KEEP")
https://virtuozzo.atlassian.net/browse/VSTOR-150231
Feature: oracle/mm: MADV_DOEXEC madvise() flag
Assisted-by: LLM
Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
---
fs/exec.c | 19 ++++++++++++++++---
mm/mmap.c | 7 ++-----
2 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/fs/exec.c b/fs/exec.c
index e861a54b491f8..62010a6d63aab 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1028,10 +1028,20 @@ static int exec_mmap(struct linux_binprm *bprm)
up_write(&tsk->signal->exec_update_lock);
return ret;
}
- if (bprm->accepts_preserved_mem) {
+ if (unlikely(bprm->accepts_preserved_mem)) {
+ /*
+ * Acquire the write lock to avoid changes to page
+ * table entries while they are copied.
+ */
+ mmap_read_unlock(old_mm);
+ ret = mmap_write_lock_killable(old_mm);
+ if (ret) {
+ up_write(&tsk->signal->exec_update_lock);
+ return ret;
+ }
ret = vma_dup_some(old_mm, mm);
if (ret) {
- mmap_read_unlock(old_mm);
+ mmap_write_unlock(old_mm);
up_write(&tsk->signal->exec_update_lock);
return ret;
}
@@ -1063,7 +1073,10 @@ static int exec_mmap(struct linux_binprm *bprm)
task_unlock(tsk);
lru_gen_use_mm(mm);
if (old_mm) {
- mmap_read_unlock(old_mm);
+ if (unlikely(bprm->accepts_preserved_mem))
+ mmap_write_unlock(old_mm);
+ else
+ mmap_read_unlock(old_mm);
BUG_ON(active_mm != old_mm);
setmax_mm_hiwater_rss(&tsk->signal->maxrss, old_mm);
mm_update_next_owner(old_mm);
diff --git a/mm/mmap.c b/mm/mmap.c
index 320f397816df9..bc508c6bd934b 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1800,12 +1800,9 @@ int vma_dup(struct vm_area_struct *old_vma, struct mm_struct *mm)
* from old_vma. Since vma_dup() is only called during exec to
* duplicate a vma from the outgoing mm into the mm of the new
* process, this effectively transfers the accounting from the old
- * vma to new one.
- * exec holds the mmap read lock on the outgoing mm at this point
- * so __vm_flags_mod() is used here to avoid an assert that the
- * mmap write lock is held which is not needed in this instance..
+ * vma to the new one.
*/
- __vm_flags_mod(old_vma, 0, VM_ACCOUNT);
+ vm_flags_clear(old_vma, VM_ACCOUNT);
#ifdef CONFIG_PADATA
ret = copy_page_range_mt(vma, old_vma);
--
2.43.0
More information about the Devel
mailing list