LCOV - code coverage report
Current view: top level - mm - pgtable-generic.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 24 0.0 %
Date: 2023-07-19 18:55:55 Functions: 0 5 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  *  mm/pgtable-generic.c
       4             :  *
       5             :  *  Generic pgtable methods declared in linux/pgtable.h
       6             :  *
       7             :  *  Copyright (C) 2010  Linus Torvalds
       8             :  */
       9             : 
      10             : #include <linux/pagemap.h>
      11             : #include <linux/hugetlb.h>
      12             : #include <linux/pgtable.h>
      13             : #include <linux/mm_inline.h>
      14             : #include <asm/tlb.h>
      15             : 
      16             : /*
      17             :  * If a p?d_bad entry is found while walking page tables, report
      18             :  * the error, before resetting entry to p?d_none.  Usually (but
      19             :  * very seldom) called out from the p?d_none_or_clear_bad macros.
      20             :  */
      21             : 
      22           0 : void pgd_clear_bad(pgd_t *pgd)
      23             : {
      24           0 :         pgd_ERROR(*pgd);
      25           0 :         pgd_clear(pgd);
      26           0 : }
      27             : 
      28             : #ifndef __PAGETABLE_P4D_FOLDED
      29             : void p4d_clear_bad(p4d_t *p4d)
      30             : {
      31             :         p4d_ERROR(*p4d);
      32             :         p4d_clear(p4d);
      33             : }
      34             : #endif
      35             : 
      36             : #ifndef __PAGETABLE_PUD_FOLDED
      37             : void pud_clear_bad(pud_t *pud)
      38             : {
      39             :         pud_ERROR(*pud);
      40             :         pud_clear(pud);
      41             : }
      42             : #endif
      43             : 
      44             : /*
      45             :  * Note that the pmd variant below can't be stub'ed out just as for p4d/pud
      46             :  * above. pmd folding is special and typically pmd_* macros refer to upper
      47             :  * level even when folded
      48             :  */
      49           0 : void pmd_clear_bad(pmd_t *pmd)
      50             : {
      51           0 :         pmd_ERROR(*pmd);
      52           0 :         pmd_clear(pmd);
      53           0 : }
      54             : 
      55             : #ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
      56             : /*
      57             :  * Only sets the access flags (dirty, accessed), as well as write
      58             :  * permission. Furthermore, we know it always gets set to a "more
      59             :  * permissive" setting, which allows most architectures to optimize
      60             :  * this. We return whether the PTE actually changed, which in turn
      61             :  * instructs the caller to do things like update__mmu_cache.  This
      62             :  * used to be done in the caller, but sparc needs minor faults to
      63             :  * force that call on sun4c so we changed this macro slightly
      64             :  */
      65           0 : int ptep_set_access_flags(struct vm_area_struct *vma,
      66             :                           unsigned long address, pte_t *ptep,
      67             :                           pte_t entry, int dirty)
      68             : {
      69           0 :         int changed = !pte_same(*ptep, entry);
      70           0 :         if (changed) {
      71           0 :                 set_pte_at(vma->vm_mm, address, ptep, entry);
      72           0 :                 flush_tlb_fix_spurious_fault(vma, address, ptep);
      73             :         }
      74           0 :         return changed;
      75             : }
      76             : #endif
      77             : 
      78             : #ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
      79           0 : int ptep_clear_flush_young(struct vm_area_struct *vma,
      80             :                            unsigned long address, pte_t *ptep)
      81             : {
      82             :         int young;
      83           0 :         young = ptep_test_and_clear_young(vma, address, ptep);
      84           0 :         if (young)
      85           0 :                 flush_tlb_page(vma, address);
      86           0 :         return young;
      87             : }
      88             : #endif
      89             : 
      90             : #ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH
      91           0 : pte_t ptep_clear_flush(struct vm_area_struct *vma, unsigned long address,
      92             :                        pte_t *ptep)
      93             : {
      94           0 :         struct mm_struct *mm = (vma)->vm_mm;
      95             :         pte_t pte;
      96           0 :         pte = ptep_get_and_clear(mm, address, ptep);
      97             :         if (pte_accessible(mm, pte))
      98           0 :                 flush_tlb_page(vma, address);
      99           0 :         return pte;
     100             : }
     101             : #endif
     102             : 
     103             : #ifdef CONFIG_TRANSPARENT_HUGEPAGE
     104             : 
     105             : #ifndef __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS
     106             : int pmdp_set_access_flags(struct vm_area_struct *vma,
     107             :                           unsigned long address, pmd_t *pmdp,
     108             :                           pmd_t entry, int dirty)
     109             : {
     110             :         int changed = !pmd_same(*pmdp, entry);
     111             :         VM_BUG_ON(address & ~HPAGE_PMD_MASK);
     112             :         if (changed) {
     113             :                 set_pmd_at(vma->vm_mm, address, pmdp, entry);
     114             :                 flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
     115             :         }
     116             :         return changed;
     117             : }
     118             : #endif
     119             : 
     120             : #ifndef __HAVE_ARCH_PMDP_CLEAR_YOUNG_FLUSH
     121             : int pmdp_clear_flush_young(struct vm_area_struct *vma,
     122             :                            unsigned long address, pmd_t *pmdp)
     123             : {
     124             :         int young;
     125             :         VM_BUG_ON(address & ~HPAGE_PMD_MASK);
     126             :         young = pmdp_test_and_clear_young(vma, address, pmdp);
     127             :         if (young)
     128             :                 flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
     129             :         return young;
     130             : }
     131             : #endif
     132             : 
     133             : #ifndef __HAVE_ARCH_PMDP_HUGE_CLEAR_FLUSH
     134             : pmd_t pmdp_huge_clear_flush(struct vm_area_struct *vma, unsigned long address,
     135             :                             pmd_t *pmdp)
     136             : {
     137             :         pmd_t pmd;
     138             :         VM_BUG_ON(address & ~HPAGE_PMD_MASK);
     139             :         VM_BUG_ON(pmd_present(*pmdp) && !pmd_trans_huge(*pmdp) &&
     140             :                            !pmd_devmap(*pmdp));
     141             :         pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp);
     142             :         flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
     143             :         return pmd;
     144             : }
     145             : 
     146             : #ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
     147             : pud_t pudp_huge_clear_flush(struct vm_area_struct *vma, unsigned long address,
     148             :                             pud_t *pudp)
     149             : {
     150             :         pud_t pud;
     151             : 
     152             :         VM_BUG_ON(address & ~HPAGE_PUD_MASK);
     153             :         VM_BUG_ON(!pud_trans_huge(*pudp) && !pud_devmap(*pudp));
     154             :         pud = pudp_huge_get_and_clear(vma->vm_mm, address, pudp);
     155             :         flush_pud_tlb_range(vma, address, address + HPAGE_PUD_SIZE);
     156             :         return pud;
     157             : }
     158             : #endif
     159             : #endif
     160             : 
     161             : #ifndef __HAVE_ARCH_PGTABLE_DEPOSIT
     162             : void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
     163             :                                 pgtable_t pgtable)
     164             : {
     165             :         assert_spin_locked(pmd_lockptr(mm, pmdp));
     166             : 
     167             :         /* FIFO */
     168             :         if (!pmd_huge_pte(mm, pmdp))
     169             :                 INIT_LIST_HEAD(&pgtable->lru);
     170             :         else
     171             :                 list_add(&pgtable->lru, &pmd_huge_pte(mm, pmdp)->lru);
     172             :         pmd_huge_pte(mm, pmdp) = pgtable;
     173             : }
     174             : #endif
     175             : 
     176             : #ifndef __HAVE_ARCH_PGTABLE_WITHDRAW
     177             : /* no "address" argument so destroys page coloring of some arch */
     178             : pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp)
     179             : {
     180             :         pgtable_t pgtable;
     181             : 
     182             :         assert_spin_locked(pmd_lockptr(mm, pmdp));
     183             : 
     184             :         /* FIFO */
     185             :         pgtable = pmd_huge_pte(mm, pmdp);
     186             :         pmd_huge_pte(mm, pmdp) = list_first_entry_or_null(&pgtable->lru,
     187             :                                                           struct page, lru);
     188             :         if (pmd_huge_pte(mm, pmdp))
     189             :                 list_del(&pgtable->lru);
     190             :         return pgtable;
     191             : }
     192             : #endif
     193             : 
     194             : #ifndef __HAVE_ARCH_PMDP_INVALIDATE
     195             : pmd_t pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
     196             :                      pmd_t *pmdp)
     197             : {
     198             :         pmd_t old = pmdp_establish(vma, address, pmdp, pmd_mkinvalid(*pmdp));
     199             :         flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
     200             :         return old;
     201             : }
     202             : #endif
     203             : 
     204             : #ifndef __HAVE_ARCH_PMDP_INVALIDATE_AD
     205             : pmd_t pmdp_invalidate_ad(struct vm_area_struct *vma, unsigned long address,
     206             :                          pmd_t *pmdp)
     207             : {
     208             :         return pmdp_invalidate(vma, address, pmdp);
     209             : }
     210             : #endif
     211             : 
     212             : #ifndef pmdp_collapse_flush
     213             : pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, unsigned long address,
     214             :                           pmd_t *pmdp)
     215             : {
     216             :         /*
     217             :          * pmd and hugepage pte format are same. So we could
     218             :          * use the same function.
     219             :          */
     220             :         pmd_t pmd;
     221             : 
     222             :         VM_BUG_ON(address & ~HPAGE_PMD_MASK);
     223             :         VM_BUG_ON(pmd_trans_huge(*pmdp));
     224             :         pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp);
     225             : 
     226             :         /* collapse entails shooting down ptes not pmd */
     227             :         flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
     228             :         return pmd;
     229             : }
     230             : #endif
     231             : #endif /* CONFIG_TRANSPARENT_HUGEPAGE */

Generated by: LCOV version 1.14