Skip to content

Commit ad2bc88

Browse files
lorenzo-stoakesakpm00
authored andcommitted
mm: remove unnecessary page_table_lock on stack expansion
Ever since commit 8d7071a ("mm: always expand the stack with the mmap write lock held") we have been expanding the stack with the mmap write lock held. This is true in all code paths: get_arg_page() -> expand_downwards() setup_arg_pages() -> expand_stack_locked() -> expand_downwards() / expand_upwards() lock_mm_and_find_vma() -> expand_stack_locked() -> expand_downwards() / expand_upwards() create_elf_tables() -> find_extend_vma_locked() -> expand_stack_locked() expand_stack() -> vma_expand_down() -> expand_downwards() expand_stack() -> vma_expand_up() -> expand_upwards() Each of which acquire the mmap write lock before doing so. Despite this, we maintain code that acquires a page table lock in the expand_upwards() and expand_downwards() code, stating that we hold a shared mmap lock and thus this is necessary. It is not, we do not have to worry about concurrent VMA expansions so we can simply drop this, and update comments accordingly. We do not even need be concerned with racing page faults, as vma_start_write() is invoked in both cases. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Lorenzo Stoakes <[email protected]> Acked-by: Linus Torvalds <[email protected]> Reviewed-by: Jann Horn <[email protected]> Acked-by: Vlastimil Babka <[email protected]> Reviewed-by: Liam R. Howlett <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 93c1e57 commit ad2bc88

File tree

1 file changed

+6
-32
lines changed

1 file changed

+6
-32
lines changed

mm/mmap.c

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,6 +1039,8 @@ static int expand_upwards(struct vm_area_struct *vma, unsigned long address)
10391039
if (!(vma->vm_flags & VM_GROWSUP))
10401040
return -EFAULT;
10411041

1042+
mmap_assert_write_locked(mm);
1043+
10421044
/* Guard against exceeding limits of the address space. */
10431045
address &= PAGE_MASK;
10441046
if (address >= (TASK_SIZE & PAGE_MASK))
@@ -1074,11 +1076,7 @@ static int expand_upwards(struct vm_area_struct *vma, unsigned long address)
10741076

10751077
/* Lock the VMA before expanding to prevent concurrent page faults */
10761078
vma_start_write(vma);
1077-
/*
1078-
* vma->vm_start/vm_end cannot change under us because the caller
1079-
* is required to hold the mmap_lock in read mode. We need the
1080-
* anon_vma lock to serialize against concurrent expand_stacks.
1081-
*/
1079+
/* We update the anon VMA tree. */
10821080
anon_vma_lock_write(vma->anon_vma);
10831081

10841082
/* Somebody else might have raced and expanded it already */
@@ -1092,16 +1090,6 @@ static int expand_upwards(struct vm_area_struct *vma, unsigned long address)
10921090
if (vma->vm_pgoff + (size >> PAGE_SHIFT) >= vma->vm_pgoff) {
10931091
error = acct_stack_growth(vma, size, grow);
10941092
if (!error) {
1095-
/*
1096-
* We only hold a shared mmap_lock lock here, so
1097-
* we need to protect against concurrent vma
1098-
* expansions. anon_vma_lock_write() doesn't
1099-
* help here, as we don't guarantee that all
1100-
* growable vmas in a mm share the same root
1101-
* anon vma. So, we reuse mm->page_table_lock
1102-
* to guard against concurrent vma expansions.
1103-
*/
1104-
spin_lock(&mm->page_table_lock);
11051093
if (vma->vm_flags & VM_LOCKED)
11061094
mm->locked_vm += grow;
11071095
vm_stat_account(mm, vma->vm_flags, grow);
@@ -1110,7 +1098,6 @@ static int expand_upwards(struct vm_area_struct *vma, unsigned long address)
11101098
/* Overwrite old entry in mtree. */
11111099
vma_iter_store(&vmi, vma);
11121100
anon_vma_interval_tree_post_update_vma(vma);
1113-
spin_unlock(&mm->page_table_lock);
11141101

11151102
perf_event_mmap(vma);
11161103
}
@@ -1137,6 +1124,8 @@ int expand_downwards(struct vm_area_struct *vma, unsigned long address)
11371124
if (!(vma->vm_flags & VM_GROWSDOWN))
11381125
return -EFAULT;
11391126

1127+
mmap_assert_write_locked(mm);
1128+
11401129
address &= PAGE_MASK;
11411130
if (address < mmap_min_addr || address < FIRST_USER_ADDRESS)
11421131
return -EPERM;
@@ -1166,11 +1155,7 @@ int expand_downwards(struct vm_area_struct *vma, unsigned long address)
11661155

11671156
/* Lock the VMA before expanding to prevent concurrent page faults */
11681157
vma_start_write(vma);
1169-
/*
1170-
* vma->vm_start/vm_end cannot change under us because the caller
1171-
* is required to hold the mmap_lock in read mode. We need the
1172-
* anon_vma lock to serialize against concurrent expand_stacks.
1173-
*/
1158+
/* We update the anon VMA tree. */
11741159
anon_vma_lock_write(vma->anon_vma);
11751160

11761161
/* Somebody else might have raced and expanded it already */
@@ -1184,16 +1169,6 @@ int expand_downwards(struct vm_area_struct *vma, unsigned long address)
11841169
if (grow <= vma->vm_pgoff) {
11851170
error = acct_stack_growth(vma, size, grow);
11861171
if (!error) {
1187-
/*
1188-
* We only hold a shared mmap_lock lock here, so
1189-
* we need to protect against concurrent vma
1190-
* expansions. anon_vma_lock_write() doesn't
1191-
* help here, as we don't guarantee that all
1192-
* growable vmas in a mm share the same root
1193-
* anon vma. So, we reuse mm->page_table_lock
1194-
* to guard against concurrent vma expansions.
1195-
*/
1196-
spin_lock(&mm->page_table_lock);
11971172
if (vma->vm_flags & VM_LOCKED)
11981173
mm->locked_vm += grow;
11991174
vm_stat_account(mm, vma->vm_flags, grow);
@@ -1203,7 +1178,6 @@ int expand_downwards(struct vm_area_struct *vma, unsigned long address)
12031178
/* Overwrite old entry in mtree. */
12041179
vma_iter_store(&vmi, vma);
12051180
anon_vma_interval_tree_post_update_vma(vma);
1206-
spin_unlock(&mm->page_table_lock);
12071181

12081182
perf_event_mmap(vma);
12091183
}

0 commit comments

Comments
 (0)