LCOV - code coverage report
Current view: top level - mm - vmacache.c (source / functions) Hit Total Coverage
Test: Real Lines: 19 19 100.0 %
Date: 2020-10-17 15:46:43 Functions: 0 3 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * Copyright (C) 2014 Davidlohr Bueso.
       4                 :            :  */
       5                 :            : #include <linux/sched/signal.h>
       6                 :            : #include <linux/sched/task.h>
       7                 :            : #include <linux/mm.h>
       8                 :            : #include <linux/vmacache.h>
       9                 :            : #include <asm/pgtable.h>
      10                 :            : 
      11                 :            : /*
      12                 :            :  * Hash based on the pmd of addr if configured with MMU, which provides a good
      13                 :            :  * hit rate for workloads with spatial locality.  Otherwise, use pages.
      14                 :            :  */
      15                 :            : #ifdef CONFIG_MMU
      16                 :            : #define VMACACHE_SHIFT  PMD_SHIFT
      17                 :            : #else
      18                 :            : #define VMACACHE_SHIFT  PAGE_SHIFT
      19                 :            : #endif
      20                 :            : #define VMACACHE_HASH(addr) ((addr >> VMACACHE_SHIFT) & VMACACHE_MASK)
      21                 :            : 
      22                 :            : /*
      23                 :            :  * This task may be accessing a foreign mm via (for example)
      24                 :            :  * get_user_pages()->find_vma().  The vmacache is task-local and this
      25                 :            :  * task's vmacache pertains to a different mm (ie, its own).  There is
      26                 :            :  * nothing we can do here.
      27                 :            :  *
      28                 :            :  * Also handle the case where a kernel thread has adopted this mm via use_mm().
      29                 :            :  * That kernel thread's vmacache is not applicable to this mm.
      30                 :            :  */
      31                 :            : static inline bool vmacache_valid_mm(struct mm_struct *mm)
      32                 :            : {
      33                 :          3 :         return current->mm == mm && !(current->flags & PF_KTHREAD);
      34                 :            : }
      35                 :            : 
      36                 :          3 : void vmacache_update(unsigned long addr, struct vm_area_struct *newvma)
      37                 :            : {
      38                 :          3 :         if (vmacache_valid_mm(newvma->vm_mm))
      39                 :          3 :                 current->vmacache.vmas[VMACACHE_HASH(addr)] = newvma;
      40                 :          3 : }
      41                 :            : 
      42                 :          3 : static bool vmacache_valid(struct mm_struct *mm)
      43                 :            : {
      44                 :            :         struct task_struct *curr;
      45                 :            : 
      46                 :          3 :         if (!vmacache_valid_mm(mm))
      47                 :            :                 return false;
      48                 :            : 
      49                 :            :         curr = current;
      50                 :          3 :         if (mm->vmacache_seqnum != curr->vmacache.seqnum) {
      51                 :            :                 /*
      52                 :            :                  * First attempt will always be invalid, initialize
      53                 :            :                  * the new cache for this task here.
      54                 :            :                  */
      55                 :          3 :                 curr->vmacache.seqnum = mm->vmacache_seqnum;
      56                 :            :                 vmacache_flush(curr);
      57                 :          3 :                 return false;
      58                 :            :         }
      59                 :            :         return true;
      60                 :            : }
      61                 :            : 
      62                 :          3 : struct vm_area_struct *vmacache_find(struct mm_struct *mm, unsigned long addr)
      63                 :            : {
      64                 :          3 :         int idx = VMACACHE_HASH(addr);
      65                 :            :         int i;
      66                 :            : 
      67                 :            :         count_vm_vmacache_event(VMACACHE_FIND_CALLS);
      68                 :            : 
      69                 :          3 :         if (!vmacache_valid(mm))
      70                 :            :                 return NULL;
      71                 :            : 
      72                 :          3 :         for (i = 0; i < VMACACHE_SIZE; i++) {
      73                 :          3 :                 struct vm_area_struct *vma = current->vmacache.vmas[idx];
      74                 :            : 
      75                 :          3 :                 if (vma) {
      76                 :            : #ifdef CONFIG_DEBUG_VM_VMACACHE
      77                 :            :                         if (WARN_ON_ONCE(vma->vm_mm != mm))
      78                 :            :                                 break;
      79                 :            : #endif
      80                 :          3 :                         if (vma->vm_start <= addr && vma->vm_end > addr) {
      81                 :            :                                 count_vm_vmacache_event(VMACACHE_FIND_HITS);
      82                 :          3 :                                 return vma;
      83                 :            :                         }
      84                 :            :                 }
      85                 :          3 :                 if (++idx == VMACACHE_SIZE)
      86                 :            :                         idx = 0;
      87                 :            :         }
      88                 :            : 
      89                 :            :         return NULL;
      90                 :            : }
      91                 :            : 
      92                 :            : #ifndef CONFIG_MMU
      93                 :            : struct vm_area_struct *vmacache_find_exact(struct mm_struct *mm,
      94                 :            :                                            unsigned long start,
      95                 :            :                                            unsigned long end)
      96                 :            : {
      97                 :            :         int idx = VMACACHE_HASH(start);
      98                 :            :         int i;
      99                 :            : 
     100                 :            :         count_vm_vmacache_event(VMACACHE_FIND_CALLS);
     101                 :            : 
     102                 :            :         if (!vmacache_valid(mm))
     103                 :            :                 return NULL;
     104                 :            : 
     105                 :            :         for (i = 0; i < VMACACHE_SIZE; i++) {
     106                 :            :                 struct vm_area_struct *vma = current->vmacache.vmas[idx];
     107                 :            : 
     108                 :            :                 if (vma && vma->vm_start == start && vma->vm_end == end) {
     109                 :            :                         count_vm_vmacache_event(VMACACHE_FIND_HITS);
     110                 :            :                         return vma;
     111                 :            :                 }
     112                 :            :                 if (++idx == VMACACHE_SIZE)
     113                 :            :                         idx = 0;
     114                 :            :         }
     115                 :            : 
     116                 :            :         return NULL;
     117                 :            : }
     118                 :            : #endif
    

Generated by: LCOV version 1.14