Skip to content

Commit 0e3a902

Browse files
punitagrawalwildea01
authored andcommitted
arm64: mm: Update perf accounting to handle poison faults
Re-organise the perf accounting for fault handling in preparation for enabling handling of hardware poison faults in subsequent commits. The change updates perf accounting to be inline with the behaviour on x86. With this update, the perf fault accounting - * Always report PERF_COUNT_SW_PAGE_FAULTS * Doesn't report anything else for VM_FAULT_ERROR (which includes hwpoison faults) * Reports PERF_COUNT_SW_PAGE_FAULTS_MAJ if it's a major fault (indicated by VM_FAULT_MAJOR) * Otherwise, reports PERF_COUNT_SW_PAGE_FAULTS_MIN Signed-off-by: Punit Agrawal <punit.agrawal@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
1 parent e7c600f commit 0e3a902

File tree

1 file changed

+36
-32
lines changed

1 file changed

+36
-32
lines changed

arch/arm64/mm/fault.c

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
359359
{
360360
struct task_struct *tsk;
361361
struct mm_struct *mm;
362-
int fault, sig, code;
362+
int fault, sig, code, major = 0;
363363
unsigned long vm_flags = VM_READ | VM_WRITE;
364364
unsigned int mm_flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
365365

@@ -398,6 +398,8 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
398398
die("Accessing user space memory outside uaccess.h routines", regs, esr);
399399
}
400400

401+
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr);
402+
401403
/*
402404
* As per x86, we may deadlock here. However, since the kernel only
403405
* validly references user space from well defined areas of the code,
@@ -421,24 +423,42 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
421423
}
422424

423425
fault = __do_page_fault(mm, addr, mm_flags, vm_flags, tsk);
426+
major |= fault & VM_FAULT_MAJOR;
424427

425-
/*
426-
* If we need to retry but a fatal signal is pending, handle the
427-
* signal first. We do not need to release the mmap_sem because it
428-
* would already be released in __lock_page_or_retry in mm/filemap.c.
429-
*/
430-
if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
431-
return 0;
428+
if (fault & VM_FAULT_RETRY) {
429+
/*
430+
* If we need to retry but a fatal signal is pending,
431+
* handle the signal first. We do not need to release
432+
* the mmap_sem because it would already be released
433+
* in __lock_page_or_retry in mm/filemap.c.
434+
*/
435+
if (fatal_signal_pending(current))
436+
return 0;
437+
438+
/*
439+
* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk of
440+
* starvation.
441+
*/
442+
if (mm_flags & FAULT_FLAG_ALLOW_RETRY) {
443+
mm_flags &= ~FAULT_FLAG_ALLOW_RETRY;
444+
mm_flags |= FAULT_FLAG_TRIED;
445+
goto retry;
446+
}
447+
}
448+
up_read(&mm->mmap_sem);
432449

433450
/*
434-
* Major/minor page fault accounting is only done on the initial
435-
* attempt. If we go through a retry, it is extremely likely that the
436-
* page will be found in page cache at that point.
451+
* Handle the "normal" (no error) case first.
437452
*/
438-
439-
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, addr);
440-
if (mm_flags & FAULT_FLAG_ALLOW_RETRY) {
441-
if (fault & VM_FAULT_MAJOR) {
453+
if (likely(!(fault & (VM_FAULT_ERROR | VM_FAULT_BADMAP |
454+
VM_FAULT_BADACCESS)))) {
455+
/*
456+
* Major/minor page fault accounting is only done
457+
* once. If we go through a retry, it is extremely
458+
* likely that the page will be found in page cache at
459+
* that point.
460+
*/
461+
if (major) {
442462
tsk->maj_flt++;
443463
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, regs,
444464
addr);
@@ -447,25 +467,9 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
447467
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, regs,
448468
addr);
449469
}
450-
if (fault & VM_FAULT_RETRY) {
451-
/*
452-
* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk of
453-
* starvation.
454-
*/
455-
mm_flags &= ~FAULT_FLAG_ALLOW_RETRY;
456-
mm_flags |= FAULT_FLAG_TRIED;
457-
goto retry;
458-
}
459-
}
460-
461-
up_read(&mm->mmap_sem);
462470

463-
/*
464-
* Handle the "normal" case first - VM_FAULT_MAJOR
465-
*/
466-
if (likely(!(fault & (VM_FAULT_ERROR | VM_FAULT_BADMAP |
467-
VM_FAULT_BADACCESS))))
468471
return 0;
472+
}
469473

470474
/*
471475
* If we are in kernel mode at this point, we have no context to

0 commit comments

Comments
 (0)