| .. | .. |
|---|
| 24 | 24 | #include <linux/mm.h> |
|---|
| 25 | 25 | #include <linux/extable.h> |
|---|
| 26 | 26 | #include <linux/uaccess.h> |
|---|
| 27 | | -#include <linux/ptrace.h> |
|---|
| 27 | +#include <linux/perf_event.h> |
|---|
| 28 | 28 | |
|---|
| 29 | 29 | #include <asm/mmu_context.h> |
|---|
| 30 | 30 | #include <asm/traps.h> |
|---|
| .. | .. |
|---|
| 48 | 48 | struct mm_struct *mm = tsk->mm; |
|---|
| 49 | 49 | int code = SEGV_MAPERR; |
|---|
| 50 | 50 | vm_fault_t fault; |
|---|
| 51 | | - unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; |
|---|
| 51 | + unsigned int flags = FAULT_FLAG_DEFAULT; |
|---|
| 52 | 52 | |
|---|
| 53 | 53 | cause >>= 2; |
|---|
| 54 | 54 | |
|---|
| .. | .. |
|---|
| 84 | 84 | if (user_mode(regs)) |
|---|
| 85 | 85 | flags |= FAULT_FLAG_USER; |
|---|
| 86 | 86 | |
|---|
| 87 | | - if (!down_read_trylock(&mm->mmap_sem)) { |
|---|
| 87 | + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); |
|---|
| 88 | + |
|---|
| 89 | + if (!mmap_read_trylock(mm)) { |
|---|
| 88 | 90 | if (!user_mode(regs) && !search_exception_tables(regs->ea)) |
|---|
| 89 | 91 | goto bad_area_nosemaphore; |
|---|
| 90 | 92 | retry: |
|---|
| 91 | | - down_read(&mm->mmap_sem); |
|---|
| 93 | + mmap_read_lock(mm); |
|---|
| 92 | 94 | } |
|---|
| 93 | 95 | |
|---|
| 94 | 96 | vma = find_vma(mm, address); |
|---|
| .. | .. |
|---|
| 132 | 134 | * make sure we exit gracefully rather than endlessly redo |
|---|
| 133 | 135 | * the fault. |
|---|
| 134 | 136 | */ |
|---|
| 135 | | - fault = handle_mm_fault(vma, address, flags); |
|---|
| 137 | + fault = handle_mm_fault(vma, address, flags, regs); |
|---|
| 136 | 138 | |
|---|
| 137 | | - if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) |
|---|
| 139 | + if (fault_signal_pending(fault, regs)) |
|---|
| 138 | 140 | return; |
|---|
| 139 | 141 | |
|---|
| 140 | 142 | if (unlikely(fault & VM_FAULT_ERROR)) { |
|---|
| .. | .. |
|---|
| 147 | 149 | BUG(); |
|---|
| 148 | 150 | } |
|---|
| 149 | 151 | |
|---|
| 150 | | - /* |
|---|
| 151 | | - * Major/minor page fault accounting is only done on the |
|---|
| 152 | | - * initial attempt. If we go through a retry, it is extremely |
|---|
| 153 | | - * likely that the page will be found in page cache at that point. |
|---|
| 154 | | - */ |
|---|
| 155 | 152 | if (flags & FAULT_FLAG_ALLOW_RETRY) { |
|---|
| 156 | | - if (fault & VM_FAULT_MAJOR) |
|---|
| 157 | | - current->maj_flt++; |
|---|
| 158 | | - else |
|---|
| 159 | | - current->min_flt++; |
|---|
| 160 | 153 | if (fault & VM_FAULT_RETRY) { |
|---|
| 161 | | - /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk |
|---|
| 162 | | - * of starvation. */ |
|---|
| 163 | | - flags &= ~FAULT_FLAG_ALLOW_RETRY; |
|---|
| 164 | 154 | flags |= FAULT_FLAG_TRIED; |
|---|
| 165 | 155 | |
|---|
| 166 | 156 | /* |
|---|
| 167 | | - * No need to up_read(&mm->mmap_sem) as we would |
|---|
| 157 | + * No need to mmap_read_unlock(mm) as we would |
|---|
| 168 | 158 | * have already released it in __lock_page_or_retry |
|---|
| 169 | 159 | * in mm/filemap.c. |
|---|
| 170 | 160 | */ |
|---|
| .. | .. |
|---|
| 173 | 163 | } |
|---|
| 174 | 164 | } |
|---|
| 175 | 165 | |
|---|
| 176 | | - up_read(&mm->mmap_sem); |
|---|
| 166 | + mmap_read_unlock(mm); |
|---|
| 177 | 167 | return; |
|---|
| 178 | 168 | |
|---|
| 179 | 169 | /* |
|---|
| .. | .. |
|---|
| 181 | 171 | * Fix it, but check if it's kernel or user first.. |
|---|
| 182 | 172 | */ |
|---|
| 183 | 173 | bad_area: |
|---|
| 184 | | - up_read(&mm->mmap_sem); |
|---|
| 174 | + mmap_read_unlock(mm); |
|---|
| 185 | 175 | |
|---|
| 186 | 176 | bad_area_nosemaphore: |
|---|
| 187 | 177 | /* User mode accesses just cause a SIGSEGV */ |
|---|
| .. | .. |
|---|
| 219 | 209 | * us unable to handle the page fault gracefully. |
|---|
| 220 | 210 | */ |
|---|
| 221 | 211 | out_of_memory: |
|---|
| 222 | | - up_read(&mm->mmap_sem); |
|---|
| 212 | + mmap_read_unlock(mm); |
|---|
| 223 | 213 | if (!user_mode(regs)) |
|---|
| 224 | 214 | goto no_context; |
|---|
| 225 | 215 | pagefault_out_of_memory(); |
|---|
| 226 | 216 | return; |
|---|
| 227 | 217 | |
|---|
| 228 | 218 | do_sigbus: |
|---|
| 229 | | - up_read(&mm->mmap_sem); |
|---|
| 219 | + mmap_read_unlock(mm); |
|---|
| 230 | 220 | |
|---|
| 231 | 221 | /* Kernel mode? Handle exceptions or die */ |
|---|
| 232 | 222 | if (!user_mode(regs)) |
|---|
| .. | .. |
|---|
| 246 | 236 | */ |
|---|
| 247 | 237 | int offset = pgd_index(address); |
|---|
| 248 | 238 | pgd_t *pgd, *pgd_k; |
|---|
| 239 | + p4d_t *p4d, *p4d_k; |
|---|
| 249 | 240 | pud_t *pud, *pud_k; |
|---|
| 250 | 241 | pmd_t *pmd, *pmd_k; |
|---|
| 251 | 242 | pte_t *pte_k; |
|---|
| .. | .. |
|---|
| 257 | 248 | goto no_context; |
|---|
| 258 | 249 | set_pgd(pgd, *pgd_k); |
|---|
| 259 | 250 | |
|---|
| 260 | | - pud = pud_offset(pgd, address); |
|---|
| 261 | | - pud_k = pud_offset(pgd_k, address); |
|---|
| 251 | + p4d = p4d_offset(pgd, address); |
|---|
| 252 | + p4d_k = p4d_offset(pgd_k, address); |
|---|
| 253 | + if (!p4d_present(*p4d_k)) |
|---|
| 254 | + goto no_context; |
|---|
| 255 | + pud = pud_offset(p4d, address); |
|---|
| 256 | + pud_k = pud_offset(p4d_k, address); |
|---|
| 262 | 257 | if (!pud_present(*pud_k)) |
|---|
| 263 | 258 | goto no_context; |
|---|
| 264 | 259 | pmd = pmd_offset(pud, address); |
|---|
| .. | .. |
|---|
| 271 | 266 | if (!pte_present(*pte_k)) |
|---|
| 272 | 267 | goto no_context; |
|---|
| 273 | 268 | |
|---|
| 274 | | - flush_tlb_one(address); |
|---|
| 269 | + flush_tlb_kernel_page(address); |
|---|
| 275 | 270 | return; |
|---|
| 276 | 271 | } |
|---|
| 277 | 272 | } |
|---|