@@ -1935,7 +1935,8 @@ static int acct_stack_growth(struct vm_area_struct *vma,
19351935 * PA-RISC uses this for its stack; IA64 for its Register Backing Store.
19361936 * vma is the last one with address > vma->vm_end. Have to extend vma.
19371937 */
1938- int expand_upwards (struct vm_area_struct * vma , unsigned long address )
1938+ int expand_upwards (struct vm_area_struct * vma , unsigned long address ,
1939+ bool write_locked )
19391940{
19401941 struct mm_struct * mm = vma -> vm_mm ;
19411942 struct vm_area_struct * next ;
@@ -1959,6 +1960,8 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
19591960 if (gap_addr < address || gap_addr > TASK_SIZE )
19601961 gap_addr = TASK_SIZE ;
19611962
1963+ if (!write_locked )
1964+ return - EAGAIN ;
19621965 next = find_vma_intersection (mm , vma -> vm_end , gap_addr );
19631966 if (next && vma_is_accessible (next )) {
19641967 if (!(next -> vm_flags & VM_GROWSUP ))
@@ -2028,7 +2031,8 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
20282031/*
20292032 * vma is the first one with address < vma->vm_start. Have to extend vma.
20302033 */
2031- int expand_downwards (struct vm_area_struct * vma , unsigned long address )
2034+ int expand_downwards (struct vm_area_struct * vma , unsigned long address ,
2035+ bool write_locked )
20322036{
20332037 struct mm_struct * mm = vma -> vm_mm ;
20342038 MA_STATE (mas , & mm -> mm_mt , vma -> vm_start , vma -> vm_start );
@@ -2042,10 +2046,13 @@ int expand_downwards(struct vm_area_struct *vma, unsigned long address)
20422046 /* Enforce stack_guard_gap */
20432047 prev = mas_prev (& mas , 0 );
20442048 /* Check that both stack segments have the same anon_vma? */
2045- if (prev && !(prev -> vm_flags & VM_GROWSDOWN ) &&
2046- vma_is_accessible (prev )) {
2047- if (address - prev -> vm_end < stack_guard_gap )
2049+ if (prev ) {
2050+ if (!(prev -> vm_flags & VM_GROWSDOWN ) &&
2051+ vma_is_accessible (prev ) &&
2052+ (address - prev -> vm_end < stack_guard_gap ))
20482053 return - ENOMEM ;
2054+ if (!write_locked && (prev -> vm_end == address ))
2055+ return - EAGAIN ;
20492056 }
20502057
20512058 if (mas_preallocate (& mas , GFP_KERNEL ))
@@ -2124,34 +2131,40 @@ static int __init cmdline_parse_stack_guard_gap(char *p)
21242131__setup ("stack_guard_gap=" , cmdline_parse_stack_guard_gap );
21252132
21262133#ifdef CONFIG_STACK_GROWSUP
2127- int expand_stack (struct vm_area_struct * vma , unsigned long address )
2134+ int expand_stack_locked (struct vm_area_struct * vma , unsigned long address ,
2135+ bool write_locked )
21282136{
2129- return expand_upwards (vma , address );
2137+ return expand_upwards (vma , address , write_locked );
21302138}
21312139
2132- struct vm_area_struct *
2133- find_extend_vma ( struct mm_struct * mm , unsigned long addr )
2140+ struct vm_area_struct * find_extend_vma_locked ( struct mm_struct * mm ,
2141+ unsigned long addr , bool write_locked )
21342142{
21352143 struct vm_area_struct * vma , * prev ;
21362144
21372145 addr &= PAGE_MASK ;
21382146 vma = find_vma_prev (mm , addr , & prev );
21392147 if (vma && (vma -> vm_start <= addr ))
21402148 return vma ;
2141- if (!prev || expand_stack (prev , addr ))
2149+ if (!prev )
2150+ return NULL ;
2151+ if (expand_stack_locked (prev , addr , write_locked ))
21422152 return NULL ;
21432153 if (prev -> vm_flags & VM_LOCKED )
21442154 populate_vma_page_range (prev , addr , prev -> vm_end , NULL );
21452155 return prev ;
21462156}
21472157#else
2148- int expand_stack (struct vm_area_struct * vma , unsigned long address )
2158+ int expand_stack_locked (struct vm_area_struct * vma , unsigned long address ,
2159+ bool write_locked )
21492160{
2150- return expand_downwards (vma , address );
2161+ if (unlikely (!(vma -> vm_flags & VM_GROWSDOWN )))
2162+ return - EINVAL ;
2163+ return expand_downwards (vma , address , write_locked );
21512164}
21522165
2153- struct vm_area_struct *
2154- find_extend_vma ( struct mm_struct * mm , unsigned long addr )
2166+ struct vm_area_struct * find_extend_vma_locked ( struct mm_struct * mm ,
2167+ unsigned long addr , bool write_locked )
21552168{
21562169 struct vm_area_struct * vma ;
21572170 unsigned long start ;
@@ -2162,17 +2175,20 @@ find_extend_vma(struct mm_struct *mm, unsigned long addr)
21622175 return NULL ;
21632176 if (vma -> vm_start <= addr )
21642177 return vma ;
2165- if (!(vma -> vm_flags & VM_GROWSDOWN ))
2166- return NULL ;
21672178 start = vma -> vm_start ;
2168- if (expand_stack (vma , addr ))
2179+ if (expand_stack_locked (vma , addr , write_locked ))
21692180 return NULL ;
21702181 if (vma -> vm_flags & VM_LOCKED )
21712182 populate_vma_page_range (vma , addr , start , NULL );
21722183 return vma ;
21732184}
21742185#endif
21752186
2187+ struct vm_area_struct * find_extend_vma (struct mm_struct * mm ,
2188+ unsigned long addr )
2189+ {
2190+ return find_extend_vma_locked (mm , addr , false);
2191+ }
21762192EXPORT_SYMBOL_GPL (find_extend_vma );
21772193
21782194/*
0 commit comments