0001
0002
0003
0004
0005 #include <linux/sched/signal.h>
0006 #include <linux/sched/task.h>
0007 #include <linux/mm.h>
0008 #include <linux/vmacache.h>
0009
0010
0011
0012
0013
0014 #ifdef CONFIG_MMU
0015 #define VMACACHE_SHIFT PMD_SHIFT
0016 #else
0017 #define VMACACHE_SHIFT PAGE_SHIFT
0018 #endif
0019 #define VMACACHE_HASH(addr) ((addr >> VMACACHE_SHIFT) & VMACACHE_MASK)
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030 static inline bool vmacache_valid_mm(struct mm_struct *mm)
0031 {
0032 return current->mm == mm && !(current->flags & PF_KTHREAD);
0033 }
0034
0035 void vmacache_update(unsigned long addr, struct vm_area_struct *newvma)
0036 {
0037 if (vmacache_valid_mm(newvma->vm_mm))
0038 current->vmacache.vmas[VMACACHE_HASH(addr)] = newvma;
0039 }
0040
0041 static bool vmacache_valid(struct mm_struct *mm)
0042 {
0043 struct task_struct *curr;
0044
0045 if (!vmacache_valid_mm(mm))
0046 return false;
0047
0048 curr = current;
0049 if (mm->vmacache_seqnum != curr->vmacache.seqnum) {
0050
0051
0052
0053
0054 curr->vmacache.seqnum = mm->vmacache_seqnum;
0055 vmacache_flush(curr);
0056 return false;
0057 }
0058 return true;
0059 }
0060
0061 struct vm_area_struct *vmacache_find(struct mm_struct *mm, unsigned long addr)
0062 {
0063 int idx = VMACACHE_HASH(addr);
0064 int i;
0065
0066 count_vm_vmacache_event(VMACACHE_FIND_CALLS);
0067
0068 if (!vmacache_valid(mm))
0069 return NULL;
0070
0071 for (i = 0; i < VMACACHE_SIZE; i++) {
0072 struct vm_area_struct *vma = current->vmacache.vmas[idx];
0073
0074 if (vma) {
0075 #ifdef CONFIG_DEBUG_VM_VMACACHE
0076 if (WARN_ON_ONCE(vma->vm_mm != mm))
0077 break;
0078 #endif
0079 if (vma->vm_start <= addr && vma->vm_end > addr) {
0080 count_vm_vmacache_event(VMACACHE_FIND_HITS);
0081 return vma;
0082 }
0083 }
0084 if (++idx == VMACACHE_SIZE)
0085 idx = 0;
0086 }
0087
0088 return NULL;
0089 }
0090
0091 #ifndef CONFIG_MMU
0092 struct vm_area_struct *vmacache_find_exact(struct mm_struct *mm,
0093 unsigned long start,
0094 unsigned long end)
0095 {
0096 int idx = VMACACHE_HASH(start);
0097 int i;
0098
0099 count_vm_vmacache_event(VMACACHE_FIND_CALLS);
0100
0101 if (!vmacache_valid(mm))
0102 return NULL;
0103
0104 for (i = 0; i < VMACACHE_SIZE; i++) {
0105 struct vm_area_struct *vma = current->vmacache.vmas[idx];
0106
0107 if (vma && vma->vm_start == start && vma->vm_end == end) {
0108 count_vm_vmacache_event(VMACACHE_FIND_HITS);
0109 return vma;
0110 }
0111 if (++idx == VMACACHE_SIZE)
0112 idx = 0;
0113 }
0114
0115 return NULL;
0116 }
0117 #endif