Skip to content

Commit 46e714c

Browse files
surenbaghdasaryanakpm00
authored andcommitted
arch/mm/fault: fix major fault accounting when retrying under per-VMA lock
A test [1] in Android test suite started failing after [2] was merged. It turns out that after handling a major fault under per-VMA lock, the process major fault counter does not register that fault as major. Before [2] read faults would be done under mmap_lock, in which case FAULT_FLAG_TRIED flag is set before retrying. That in turn causes mm_account_fault() to account the fault as major once retry completes. With per-VMA locks we often retry because a fault can't be handled without locking the whole mm using mmap_lock. Therefore such retries do not set FAULT_FLAG_TRIED flag. This logic does not work after [2] because we can now handle read major faults under per-VMA lock and upon retry the fact there was a major fault gets lost. Fix this by setting FAULT_FLAG_TRIED after retrying under per-VMA lock if VM_FAULT_MAJOR was returned. Ideally we would use an additional VM_FAULT bit to indicate the reason for the retry (could not handle under per-VMA lock vs other reason) but this simpler solution seems to work, so keeping it simple. [1] https://cs.android.com/android/platform/superproject/+/master:test/vts-testcase/kernel/api/drop_caches_prop/drop_caches_test.cpp [2] https://lore.kernel.org/all/[email protected]/ Link: https://lkml.kernel.org/r/[email protected] Fixes: 12214eb ("mm: handle read faults under the VMA lock") Signed-off-by: Suren Baghdasaryan <[email protected]> Cc: Matthew Wilcox <[email protected]> Cc: Alexander Gordeev <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: Christophe Leroy <[email protected]> Cc: Dave Hansen <[email protected]> Cc: Gerald Schaefer <[email protected]> Cc: Michael Ellerman <[email protected]> Cc: Palmer Dabbelt <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Will Deacon <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent c28ac3c commit 46e714c

File tree

5 files changed

+11
-0
lines changed

5 files changed

+11
-0
lines changed

arch/arm64/mm/fault.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,8 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,
607607
goto done;
608608
}
609609
count_vm_vma_lock_event(VMA_LOCK_RETRY);
610+
if (fault & VM_FAULT_MAJOR)
611+
mm_flags |= FAULT_FLAG_TRIED;
610612

611613
/* Quick path to respond to signals */
612614
if (fault_signal_pending(fault, regs)) {

arch/powerpc/mm/fault.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,8 @@ static int ___do_page_fault(struct pt_regs *regs, unsigned long address,
497497
goto done;
498498
}
499499
count_vm_vma_lock_event(VMA_LOCK_RETRY);
500+
if (fault & VM_FAULT_MAJOR)
501+
flags |= FAULT_FLAG_TRIED;
500502

501503
if (fault_signal_pending(fault, regs))
502504
return user_mode(regs) ? 0 : SIGBUS;

arch/riscv/mm/fault.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ void handle_page_fault(struct pt_regs *regs)
304304
goto done;
305305
}
306306
count_vm_vma_lock_event(VMA_LOCK_RETRY);
307+
if (fault & VM_FAULT_MAJOR)
308+
flags |= FAULT_FLAG_TRIED;
307309

308310
if (fault_signal_pending(fault, regs)) {
309311
if (!user_mode(regs))

arch/s390/mm/fault.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,9 @@ static void do_exception(struct pt_regs *regs, int access)
337337
return;
338338
}
339339
count_vm_vma_lock_event(VMA_LOCK_RETRY);
340+
if (fault & VM_FAULT_MAJOR)
341+
flags |= FAULT_FLAG_TRIED;
342+
340343
/* Quick path to respond to signals */
341344
if (fault_signal_pending(fault, regs)) {
342345
if (!user_mode(regs))

arch/x86/mm/fault.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1370,6 +1370,8 @@ void do_user_addr_fault(struct pt_regs *regs,
13701370
goto done;
13711371
}
13721372
count_vm_vma_lock_event(VMA_LOCK_RETRY);
1373+
if (fault & VM_FAULT_MAJOR)
1374+
flags |= FAULT_FLAG_TRIED;
13731375

13741376
/* Quick path to respond to signals */
13751377
if (fault_signal_pending(fault, regs)) {

0 commit comments

Comments
 (0)