Skip to content

Commit

Permalink
Fix OOPS in mmap_region() when merging adjacent VM_LOCKED file segments
Browse files Browse the repository at this point in the history
As of commit ba470de ("map: handle
mlocked pages during map, remap, unmap") we now use the 'vma' variable
at the end of mmap_region() to handle the page-in of newly mapped
mlocked pages.

However, if we merged adjacent vma's together, the vma we're using may
be stale.  We historically consciously avoided using it after the merge
operation, but that got overlooked when redoing the locked page
handling.

This commit simplifies mmap_region() by doing any vma merges early,
avoiding the issue entirely, and 'vma' will always be valid.  As pointed
out by Hugh Dickins, this depends on any drivers that change the page
offset of flags to have set one of the VM_SPECIAL bits (so that they
cannot trigger the early merge logic), but that's true in general.

Reported-and-tested-by: Maksim Yevmenkin <maksim.yevmenkin@gmail.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
Cc: Nick Piggin <npiggin@suse.de>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Linus Torvalds committed Jan 30, 2009
1 parent 18e352e commit de33c8d
Showing 1 changed file with 6 additions and 20 deletions.
26 changes: 6 additions & 20 deletions mm/mmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1134,16 +1134,11 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
}

/*
* Can we just expand an old private anonymous mapping?
* The VM_SHARED test is necessary because shmem_zero_setup
* will create the file object for a shared anonymous map below.
* Can we just expand an old mapping?
*/
if (!file && !(vm_flags & VM_SHARED)) {
vma = vma_merge(mm, prev, addr, addr + len, vm_flags,
NULL, NULL, pgoff, NULL);
if (vma)
goto out;
}
vma = vma_merge(mm, prev, addr, addr + len, vm_flags, NULL, file, pgoff, NULL);
if (vma)
goto out;

/*
* Determine the object being mapped and call the appropriate
Expand Down Expand Up @@ -1206,17 +1201,8 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
if (vma_wants_writenotify(vma))
vma->vm_page_prot = vm_get_page_prot(vm_flags & ~VM_SHARED);

if (file && vma_merge(mm, prev, addr, vma->vm_end,
vma->vm_flags, NULL, file, pgoff, vma_policy(vma))) {
mpol_put(vma_policy(vma));
kmem_cache_free(vm_area_cachep, vma);
fput(file);
if (vm_flags & VM_EXECUTABLE)
removed_exe_file_vma(mm);
} else {
vma_link(mm, vma, prev, rb_link, rb_parent);
file = vma->vm_file;
}
vma_link(mm, vma, prev, rb_link, rb_parent);
file = vma->vm_file;

/* Once vma denies write, undo our temporary denial count */
if (correct_wcount)
Expand Down

0 comments on commit de33c8d

Please sign in to comment.