| 1 | // SPDX-License-Identifier: GPL-2.0 | 
|---|
| 2 | #include <linux/hugetlb.h> | 
|---|
| 3 | #include <asm-generic/tlb.h> | 
|---|
| 4 | #include <asm/pgalloc.h> | 
|---|
| 5 |  | 
|---|
| 6 | #include "internal.h" | 
|---|
| 7 |  | 
|---|
| 8 | bool reclaim_pt_is_enabled(unsigned long start, unsigned long end, | 
|---|
| 9 | struct zap_details *details) | 
|---|
| 10 | { | 
|---|
| 11 | return details && details->reclaim_pt && (end - start >= PMD_SIZE); | 
|---|
| 12 | } | 
|---|
| 13 |  | 
|---|
| 14 | bool try_get_and_clear_pmd(struct mm_struct *mm, pmd_t *pmd, pmd_t *pmdval) | 
|---|
| 15 | { | 
|---|
| 16 | spinlock_t *pml = pmd_lockptr(mm, pmd); | 
|---|
| 17 |  | 
|---|
| 18 | if (!spin_trylock(lock: pml)) | 
|---|
| 19 | return false; | 
|---|
| 20 |  | 
|---|
| 21 | *pmdval = pmdp_get_lockless(pmdp: pmd); | 
|---|
| 22 | pmd_clear(pmd); | 
|---|
| 23 | spin_unlock(lock: pml); | 
|---|
| 24 |  | 
|---|
| 25 | return true; | 
|---|
| 26 | } | 
|---|
| 27 |  | 
|---|
| 28 | void free_pte(struct mm_struct *mm, unsigned long addr, struct mmu_gather *tlb, | 
|---|
| 29 | pmd_t pmdval) | 
|---|
| 30 | { | 
|---|
| 31 | pte_free_tlb(tlb, pmd_pgtable(pmdval), addr); | 
|---|
| 32 | mm_dec_nr_ptes(mm); | 
|---|
| 33 | } | 
|---|
| 34 |  | 
|---|
| 35 | void try_to_free_pte(struct mm_struct *mm, pmd_t *pmd, unsigned long addr, | 
|---|
| 36 | struct mmu_gather *tlb) | 
|---|
| 37 | { | 
|---|
| 38 | pmd_t pmdval; | 
|---|
| 39 | spinlock_t *pml, *ptl = NULL; | 
|---|
| 40 | pte_t *start_pte, *pte; | 
|---|
| 41 | int i; | 
|---|
| 42 |  | 
|---|
| 43 | pml = pmd_lock(mm, pmd); | 
|---|
| 44 | start_pte = pte_offset_map_rw_nolock(mm, pmd, addr, pmdvalp: &pmdval, ptlp: &ptl); | 
|---|
| 45 | if (!start_pte) | 
|---|
| 46 | goto out_ptl; | 
|---|
| 47 | if (ptl != pml) | 
|---|
| 48 | spin_lock_nested(ptl, SINGLE_DEPTH_NESTING); | 
|---|
| 49 |  | 
|---|
| 50 | /* Check if it is empty PTE page */ | 
|---|
| 51 | for (i = 0, pte = start_pte; i < PTRS_PER_PTE; i++, pte++) { | 
|---|
| 52 | if (!pte_none(pte: ptep_get(ptep: pte))) | 
|---|
| 53 | goto out_ptl; | 
|---|
| 54 | } | 
|---|
| 55 | pte_unmap(pte: start_pte); | 
|---|
| 56 |  | 
|---|
| 57 | pmd_clear(pmd); | 
|---|
| 58 |  | 
|---|
| 59 | if (ptl != pml) | 
|---|
| 60 | spin_unlock(lock: ptl); | 
|---|
| 61 | spin_unlock(lock: pml); | 
|---|
| 62 |  | 
|---|
| 63 | free_pte(mm, addr, tlb, pmdval); | 
|---|
| 64 |  | 
|---|
| 65 | return; | 
|---|
| 66 | out_ptl: | 
|---|
| 67 | if (start_pte) | 
|---|
| 68 | pte_unmap_unlock(start_pte, ptl); | 
|---|
| 69 | if (ptl != pml) | 
|---|
| 70 | spin_unlock(lock: pml); | 
|---|
| 71 | } | 
|---|
| 72 |  | 
|---|