Use the general page fault accounting by passing regs into handle_mm_fault(). It naturally solve the issue of multiple page fault accounting when page fault retry happened. Fix PERF_COUNT_SW_PAGE_FAULTS perf event manually for page fault retries, by moving it before taking mmap_sem.
Unified · Split
| @@ -121,6 +121,8 @@ void do_page_fault(unsigned long entry, unsigned long addr, · 120 unmodified lines | |||
| 121 | if (unlikely(faulthandler_disabled() || !mm)) | 121 | if (unlikely(faulthandler_disabled() || !mm)) |
| 122 | goto no_context; | 122 | goto no_context; |
| 123 | 123 | ||
| 124 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr); | ||
| 125 | |||
| 124 | /* | 126 | /* |
| 125 | * As per x86, we may deadlock here. However, since the kernel only | 127 | * As per x86, we may deadlock here. However, since the kernel only |
| 126 | * validly references user space from well defined areas of the code, | 128 | * validly references user space from well defined areas of the code, |
| @@ -206,7 +208,7 @@ good_area: · 79 unmodified lines | |||
| 206 | * the fault. | 208 | * the fault. |
| 207 | */ | 209 | */ |
| 208 | 210 | ||
| 209 | fault = handle_mm_fault(vma, addr, flags, NULL); | 211 | fault = handle_mm_fault(vma, addr, flags, regs); |
| 210 | 212 | ||
| 211 | /* | 213 | /* |
| 212 | * If we need to retry but a fatal signal is pending, handle the | 214 | * If we need to retry but a fatal signal is pending, handle the |
| @@ -228,22 +230,7 @@ good_area: · 15 unmodified lines | |||
| 228 | goto bad_area; | 230 | goto bad_area; |
| 229 | } | 231 | } |
| 230 | 232 | ||
| 231 | /* | ||
| 232 | * Major/minor page fault accounting is only done on the initial | ||
| 233 | * attempt. If we go through a retry, it is extremely likely that the | ||
| 234 | * page will be found in page cache at that point. | ||
| 235 | */ | ||
| 236 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr); | ||
| 237 | if (flags & FAULT_FLAG_ALLOW_RETRY) { | 233 | if (flags & FAULT_FLAG_ALLOW_RETRY) { |
| 238 | if (fault & VM_FAULT_MAJOR) { | ||
| 239 | tsk->maj_flt++; | ||
| 240 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, | ||
| 241 | 1, regs, addr); | ||
| 242 | } else { | ||
| 243 | tsk->min_flt++; | ||
| 244 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, | ||
| 245 | 1, regs, addr); | ||
| 246 | } | ||
| 247 | if (fault & VM_FAULT_RETRY) { | 234 | if (fault & VM_FAULT_RETRY) { |
| 248 | flags |= FAULT_FLAG_TRIED; | 235 | flags |= FAULT_FLAG_TRIED; |
| 249 | 236 | ||