diff options
Diffstat (limited to 'mm/hugetlb.c')
| -rw-r--r-- | mm/hugetlb.c | 35 |
1 files changed, 21 insertions, 14 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 901ac523a1c3..a1b30d45459e 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
| @@ -274,21 +274,22 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, | |||
| 274 | { | 274 | { |
| 275 | pte_t *src_pte, *dst_pte, entry; | 275 | pte_t *src_pte, *dst_pte, entry; |
| 276 | struct page *ptepage; | 276 | struct page *ptepage; |
| 277 | unsigned long addr = vma->vm_start; | 277 | unsigned long addr; |
| 278 | unsigned long end = vma->vm_end; | ||
| 279 | 278 | ||
| 280 | while (addr < end) { | 279 | for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) { |
| 281 | dst_pte = huge_pte_alloc(dst, addr); | 280 | dst_pte = huge_pte_alloc(dst, addr); |
| 282 | if (!dst_pte) | 281 | if (!dst_pte) |
| 283 | goto nomem; | 282 | goto nomem; |
| 283 | spin_lock(&src->page_table_lock); | ||
| 284 | src_pte = huge_pte_offset(src, addr); | 284 | src_pte = huge_pte_offset(src, addr); |
| 285 | BUG_ON(!src_pte || pte_none(*src_pte)); /* prefaulted */ | 285 | if (src_pte && !pte_none(*src_pte)) { |
| 286 | entry = *src_pte; | 286 | entry = *src_pte; |
| 287 | ptepage = pte_page(entry); | 287 | ptepage = pte_page(entry); |
| 288 | get_page(ptepage); | 288 | get_page(ptepage); |
| 289 | add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE); | 289 | add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE); |
| 290 | set_huge_pte_at(dst, addr, dst_pte, entry); | 290 | set_huge_pte_at(dst, addr, dst_pte, entry); |
| 291 | addr += HPAGE_SIZE; | 291 | } |
| 292 | spin_unlock(&src->page_table_lock); | ||
| 292 | } | 293 | } |
| 293 | return 0; | 294 | return 0; |
| 294 | 295 | ||
| @@ -323,8 +324,8 @@ void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, | |||
| 323 | 324 | ||
| 324 | page = pte_page(pte); | 325 | page = pte_page(pte); |
| 325 | put_page(page); | 326 | put_page(page); |
| 327 | add_mm_counter(mm, rss, - (HPAGE_SIZE / PAGE_SIZE)); | ||
| 326 | } | 328 | } |
| 327 | add_mm_counter(mm, rss, -((end - start) >> PAGE_SHIFT)); | ||
| 328 | flush_tlb_range(vma, start, end); | 329 | flush_tlb_range(vma, start, end); |
| 329 | } | 330 | } |
| 330 | 331 | ||
| @@ -403,6 +404,7 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
| 403 | BUG_ON(!is_vm_hugetlb_page(vma)); | 404 | BUG_ON(!is_vm_hugetlb_page(vma)); |
| 404 | 405 | ||
| 405 | vpfn = vaddr/PAGE_SIZE; | 406 | vpfn = vaddr/PAGE_SIZE; |
| 407 | spin_lock(&mm->page_table_lock); | ||
| 406 | while (vaddr < vma->vm_end && remainder) { | 408 | while (vaddr < vma->vm_end && remainder) { |
| 407 | 409 | ||
| 408 | if (pages) { | 410 | if (pages) { |
| @@ -415,8 +417,13 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
| 415 | * indexing below to work. */ | 417 | * indexing below to work. */ |
| 416 | pte = huge_pte_offset(mm, vaddr & HPAGE_MASK); | 418 | pte = huge_pte_offset(mm, vaddr & HPAGE_MASK); |
| 417 | 419 | ||
| 418 | /* hugetlb should be locked, and hence, prefaulted */ | 420 | /* the hugetlb file might have been truncated */ |
| 419 | WARN_ON(!pte || pte_none(*pte)); | 421 | if (!pte || pte_none(*pte)) { |
| 422 | remainder = 0; | ||
| 423 | if (!i) | ||
| 424 | i = -EFAULT; | ||
| 425 | break; | ||
| 426 | } | ||
| 420 | 427 | ||
| 421 | page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)]; | 428 | page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)]; |
| 422 | 429 | ||
| @@ -434,7 +441,7 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
| 434 | --remainder; | 441 | --remainder; |
| 435 | ++i; | 442 | ++i; |
| 436 | } | 443 | } |
| 437 | 444 | spin_unlock(&mm->page_table_lock); | |
| 438 | *length = remainder; | 445 | *length = remainder; |
| 439 | *position = vaddr; | 446 | *position = vaddr; |
| 440 | 447 | ||
