Skip to content

Commit

Permalink
fs/hugetlbfs/inode.c: fix bugs in hugetlb_vmtruncate_list()
Browse files Browse the repository at this point in the history
Hillf Danton noticed bugs in the hugetlb_vmtruncate_list routine.  The
argument end is of type pgoff_t.  It was being converted to a vaddr
offset and passed to unmap_hugepage_range.  However, end was also being
used as an argument to the vma_interval_tree_foreach controlling loop.
In addition, the conversion of end to vaddr offset was incorrect.

hugetlb_vmtruncate_list is called as part of a file truncate or
fallocate hole punch operation.

When truncating a hugetlbfs file, this bug could prevent some pages from
being unmapped.  This is possible if there are multiple vmas mapping the
file, and there is a sufficiently sized hole between the mappings.  The
size of the hole between two vmas (A,B) must be such that the starting
virtual address of B is greater than (ending virtual address of A <<
PAGE_SHIFT).  In this case, the pages in B would not be unmapped.  If
pages are not properly unmapped during truncate, the following BUG is
hit:

	kernel BUG at fs/hugetlbfs/inode.c:428!

In the fallocate hole punch case, this bug could prevent pages from
being unmapped as in the truncate case.  However, for hole punch the
result is that unmapped pages will not be removed during the operation.
For hole punch, it is also possible that more pages than desired will be
unmapped.  This unnecessary unmapping will cause page faults to
reestablish the mappings on subsequent page access.

Fixes: 1bfad99 (" hugetlbfs: hugetlb_vmtruncate_list() needs to take a range")Reported-by: Hillf Danton <[email protected]>
Signed-off-by: Mike Kravetz <[email protected]>
Cc: Hugh Dickins <[email protected]>
Cc: Naoya Horiguchi <[email protected]>
Cc: Davidlohr Bueso <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: <[email protected]>	[4.3]
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
mjkravetz authored and torvalds committed Jan 16, 2016
1 parent 9f8bdb3 commit 9aacdd3
Showing 1 changed file with 11 additions and 8 deletions.
19 changes: 11 additions & 8 deletions fs/hugetlbfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,7 @@ hugetlb_vmdelete_list(struct rb_root *root, pgoff_t start, pgoff_t end)
*/
vma_interval_tree_foreach(vma, root, start, end ? end : ULONG_MAX) {
unsigned long v_offset;
unsigned long v_end;

/*
* Can the expression below overflow on 32-bit arches?
Expand All @@ -475,15 +476,17 @@ hugetlb_vmdelete_list(struct rb_root *root, pgoff_t start, pgoff_t end)
else
v_offset = 0;

if (end) {
end = ((end - start) << PAGE_SHIFT) +
vma->vm_start + v_offset;
if (end > vma->vm_end)
end = vma->vm_end;
} else
end = vma->vm_end;
if (!end)
v_end = vma->vm_end;
else {
v_end = ((end - vma->vm_pgoff) << PAGE_SHIFT)
+ vma->vm_start;
if (v_end > vma->vm_end)
v_end = vma->vm_end;
}

unmap_hugepage_range(vma, vma->vm_start + v_offset, end, NULL);
unmap_hugepage_range(vma, vma->vm_start + v_offset, v_end,
NULL);
}
}

Expand Down

0 comments on commit 9aacdd3

Please sign in to comment.