|
24 | 24 |
|
25 | 25 | #include <asm/page.h> |
26 | 26 | #include <asm/pgtable.h> |
27 | | -#include <linux/io.h> |
| 27 | +#include <asm/tlb.h> |
28 | 28 |
|
| 29 | +#include <linux/io.h> |
29 | 30 | #include <linux/hugetlb.h> |
30 | 31 | #include <linux/node.h> |
31 | 32 | #include "internal.h" |
@@ -2310,30 +2311,26 @@ static int is_hugetlb_entry_hwpoisoned(pte_t pte) |
2310 | 2311 | return 0; |
2311 | 2312 | } |
2312 | 2313 |
|
2313 | | -void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, |
2314 | | - unsigned long end, struct page *ref_page) |
| 2314 | +void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma, |
| 2315 | + unsigned long start, unsigned long end, |
| 2316 | + struct page *ref_page) |
2315 | 2317 | { |
| 2318 | + int force_flush = 0; |
2316 | 2319 | struct mm_struct *mm = vma->vm_mm; |
2317 | 2320 | unsigned long address; |
2318 | 2321 | pte_t *ptep; |
2319 | 2322 | pte_t pte; |
2320 | 2323 | struct page *page; |
2321 | | - struct page *tmp; |
2322 | 2324 | struct hstate *h = hstate_vma(vma); |
2323 | 2325 | unsigned long sz = huge_page_size(h); |
2324 | 2326 |
|
2325 | | - /* |
2326 | | - * A page gathering list, protected by per file i_mmap_mutex. The |
2327 | | - * lock is used to avoid list corruption from multiple unmapping |
2328 | | - * of the same page since we are using page->lru. |
2329 | | - */ |
2330 | | - LIST_HEAD(page_list); |
2331 | | - |
2332 | 2327 | WARN_ON(!is_vm_hugetlb_page(vma)); |
2333 | 2328 | BUG_ON(start & ~huge_page_mask(h)); |
2334 | 2329 | BUG_ON(end & ~huge_page_mask(h)); |
2335 | 2330 |
|
| 2331 | + tlb_start_vma(tlb, vma); |
2336 | 2332 | mmu_notifier_invalidate_range_start(mm, start, end); |
| 2333 | +again: |
2337 | 2334 | spin_lock(&mm->page_table_lock); |
2338 | 2335 | for (address = start; address < end; address += sz) { |
2339 | 2336 | ptep = huge_pte_offset(mm, address); |
@@ -2372,30 +2369,45 @@ void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, |
2372 | 2369 | } |
2373 | 2370 |
|
2374 | 2371 | pte = huge_ptep_get_and_clear(mm, address, ptep); |
| 2372 | + tlb_remove_tlb_entry(tlb, ptep, address); |
2375 | 2373 | if (pte_dirty(pte)) |
2376 | 2374 | set_page_dirty(page); |
2377 | | - list_add(&page->lru, &page_list); |
2378 | 2375 |
|
| 2376 | + page_remove_rmap(page); |
| 2377 | + force_flush = !__tlb_remove_page(tlb, page); |
| 2378 | + if (force_flush) |
| 2379 | + break; |
2379 | 2380 | /* Bail out after unmapping reference page if supplied */ |
2380 | 2381 | if (ref_page) |
2381 | 2382 | break; |
2382 | 2383 | } |
2383 | | - flush_tlb_range(vma, start, end); |
2384 | 2384 | spin_unlock(&mm->page_table_lock); |
2385 | | - mmu_notifier_invalidate_range_end(mm, start, end); |
2386 | | - list_for_each_entry_safe(page, tmp, &page_list, lru) { |
2387 | | - page_remove_rmap(page); |
2388 | | - list_del(&page->lru); |
2389 | | - put_page(page); |
| 2385 | + /* |
| 2386 | + * mmu_gather ran out of room to batch pages, we break out of |
| 2387 | + * the PTE lock to avoid doing the potential expensive TLB invalidate |
| 2388 | + * and page-free while holding it. |
| 2389 | + */ |
| 2390 | + if (force_flush) { |
| 2391 | + force_flush = 0; |
| 2392 | + tlb_flush_mmu(tlb); |
| 2393 | + if (address < end && !ref_page) |
| 2394 | + goto again; |
2390 | 2395 | } |
| 2396 | + mmu_notifier_invalidate_range_end(mm, start, end); |
| 2397 | + tlb_end_vma(tlb, vma); |
2391 | 2398 | } |
2392 | 2399 |
|
2393 | 2400 | void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, |
2394 | 2401 | unsigned long end, struct page *ref_page) |
2395 | 2402 | { |
2396 | | - mutex_lock(&vma->vm_file->f_mapping->i_mmap_mutex); |
2397 | | - __unmap_hugepage_range(vma, start, end, ref_page); |
2398 | | - mutex_unlock(&vma->vm_file->f_mapping->i_mmap_mutex); |
| 2403 | + struct mm_struct *mm; |
| 2404 | + struct mmu_gather tlb; |
| 2405 | + |
| 2406 | + mm = vma->vm_mm; |
| 2407 | + |
| 2408 | + tlb_gather_mmu(&tlb, mm, 0); |
| 2409 | + __unmap_hugepage_range(&tlb, vma, start, end, ref_page); |
| 2410 | + tlb_finish_mmu(&tlb, start, end); |
2399 | 2411 | } |
2400 | 2412 |
|
2401 | 2413 | /* |
@@ -2440,9 +2452,8 @@ static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma, |
2440 | 2452 | * from the time of fork. This would look like data corruption |
2441 | 2453 | */ |
2442 | 2454 | if (!is_vma_resv_set(iter_vma, HPAGE_RESV_OWNER)) |
2443 | | - __unmap_hugepage_range(iter_vma, |
2444 | | - address, address + huge_page_size(h), |
2445 | | - page); |
| 2455 | + unmap_hugepage_range(iter_vma, address, |
| 2456 | + address + huge_page_size(h), page); |
2446 | 2457 | } |
2447 | 2458 | mutex_unlock(&mapping->i_mmap_mutex); |
2448 | 2459 |
|
|
0 commit comments