unsigned long addr, struct pt_regs *regs)
{
struct vm_area_struct *vma;
+ int err;
if (!get_mmap_lock_carefully(mm, regs))
return NULL;
* Well, dang. We might still be successful, but only
* if we can extend a vma to do so.
*/
- if (!vma || !(vma->vm_flags & VM_GROWSDOWN)) {
+ if (unlikely(!vma)) {
mmap_read_unlock(mm);
return NULL;
}
-
- if (!upgrade_mmap_lock_carefully(mm, regs))
- return NULL;
-
- vma = find_extend_vma(mm, addr);
- if (!vma) {
- mmap_write_unlock(mm);
- return NULL;
+ err = expand_stack(vma, addr, false);
+ if (unlikely(err)){
+ if (err != -EAGAIN) {
+ mmap_read_unlock(mm);
+ return NULL;
+ }
+ if (!upgrade_mmap_lock_carefully(mm, regs))
+ return NULL;
+ vma = find_vma(mm, addr);
+ if (!vma || expand_stack(vma, addr, true)) {
+ mmap_write_unlock(mm);
+ return NULL;
+ }
+ mmap_write_downgrade(mm);
}
- mmap_write_downgrade(mm);
return vma;
}
#endif
return vma;
start = vma->vm_start;
err = expand_stack(vma, addr, write_locked);
- if (unlikely(err == -EAGAIN)) {
- mmap_read_unlock(mm);
- mmap_write_lock(mm);
+ if (unlikely(err)) {
+ if (err != -EAGAIN)
+ return NULL;
+ if (!upgrade_mmap_lock_carefully(mm, NULL))
+ return NULL;
vma = find_vma(mm, addr);
- if (vma)
- err = expand_stack(vma, addr, true);
+ if (!vma || expand_stack(vma, addr, true)) {
+ mmap_write_downgrade(mm);
+ return NULL;
+ }
mmap_write_downgrade(mm);
}
- if (err)
- return NULL;
if (vma->vm_flags & VM_LOCKED)
populate_vma_page_range(vma, addr, start, NULL);
return vma;