Skip to content

Commit

Permalink
[PATCH] mm: hugetlb truncation fixes
Browse files Browse the repository at this point in the history
hugetlbfs allows truncation of its files (should it?), but hugetlb.c often
forgets that: crashes and misaccounting ensue.

copy_hugetlb_page_range better grab the src page_table_lock since we don't
want to guess what happens if concurrently truncated.  unmap_hugepage_range
rss accounting must not assume the full range was mapped.  follow_hugetlb_page
must guard with page_table_lock and be prepared to exit early.

Restyle copy_hugetlb_page_range with a for loop like the others there.

Signed-off-by: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Hugh Dickins authored and Linus Torvalds committed Oct 20, 2005
1 parent e03d13e commit 1c59827
Showing 1 changed file with 21 additions and 14 deletions.
35 changes: 21 additions & 14 deletions mm/hugetlb.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,21 +274,22 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
{
pte_t *src_pte, *dst_pte, entry;
struct page *ptepage;
unsigned long addr = vma->vm_start;
unsigned long end = vma->vm_end;
unsigned long addr;

while (addr < end) {
for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) {
dst_pte = huge_pte_alloc(dst, addr);
if (!dst_pte)
goto nomem;
spin_lock(&src->page_table_lock);
src_pte = huge_pte_offset(src, addr);
BUG_ON(!src_pte || pte_none(*src_pte)); /* prefaulted */
entry = *src_pte;
ptepage = pte_page(entry);
get_page(ptepage);
add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
set_huge_pte_at(dst, addr, dst_pte, entry);
addr += HPAGE_SIZE;
if (src_pte && !pte_none(*src_pte)) {
entry = *src_pte;
ptepage = pte_page(entry);
get_page(ptepage);
add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE);
set_huge_pte_at(dst, addr, dst_pte, entry);
}
spin_unlock(&src->page_table_lock);
}
return 0;

Expand Down Expand Up @@ -323,8 +324,8 @@ void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,

page = pte_page(pte);
put_page(page);
add_mm_counter(mm, rss, - (HPAGE_SIZE / PAGE_SIZE));
}
add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT));
flush_tlb_range(vma, start, end);
}

Expand Down Expand Up @@ -403,6 +404,7 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
BUG_ON(!is_vm_hugetlb_page(vma));

vpfn = vaddr/PAGE_SIZE;
spin_lock(&mm->page_table_lock);
while (vaddr < vma->vm_end && remainder) {

if (pages) {
Expand All @@ -415,8 +417,13 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
* indexing below to work. */
pte = huge_pte_offset(mm, vaddr & HPAGE_MASK);

/* hugetlb should be locked, and hence, prefaulted */
WARN_ON(!pte || pte_none(*pte));
/* the hugetlb file might have been truncated */
if (!pte || pte_none(*pte)) {
remainder = 0;
if (!i)
i = -EFAULT;
break;
}

page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)];

Expand All @@ -434,7 +441,7 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
--remainder;
++i;
}

spin_unlock(&mm->page_table_lock);
*length = remainder;
*position = vaddr;

Expand Down

0 comments on commit 1c59827

Please sign in to comment.