.. | .. |
---|
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 | } |
---|