|
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