From: Kefeng Wang <hidden> Date: 2023-08-21 12:31:21
Add a generic VMA lock-based page fault handler in mm core, and convert
architectures to use it, which eliminate architectures's duplicated
codes.
With it, we can avoid multiple changes in architectures's code if we
add new feature or bugfix, in the end, enable this feature on ARM32
and Loongarch.
This is based on next-20230817, only built test.
v2:
- convert "int arch_vma_check_access()" to "bool arch_vma_access_error()"
still use __weak function for arch_vma_access_error(), which avoid to
declare access_error() in architecture's(x86/powerpc/riscv/loongarch)
headfile.
- re-use struct vm_fault instead of adding new struct vm_locked_fault,
per Matthew Wilcox, add necessary pt_regs/fault error code/vm flags
into vm_fault since they could be used in arch_vma_access_error()
- add special VM_FAULT_NONE and make try_vma_locked_page_fault() to
return vm_fault_t
Kefeng Wang (10):
mm: add a generic VMA lock-based page fault handler
arm64: mm: use try_vma_locked_page_fault()
x86: mm: use try_vma_locked_page_fault()
s390: mm: use try_vma_locked_page_fault()
powerpc: mm: use try_vma_locked_page_fault()
riscv: mm: use try_vma_locked_page_fault()
ARM: mm: try VMA lock-based page fault handling first
loongarch: mm: cleanup __do_page_fault()
loongarch: mm: add access_error() helper
loongarch: mm: try VMA lock-based page fault handling first
arch/arm/Kconfig | 1 +
arch/arm/mm/fault.c | 35 ++++++++----
arch/arm64/mm/fault.c | 60 ++++++++-------------
arch/loongarch/Kconfig | 1 +
arch/loongarch/mm/fault.c | 111 ++++++++++++++++++++++----------------
arch/powerpc/mm/fault.c | 66 +++++++++++------------
arch/riscv/mm/fault.c | 58 +++++++++-----------
arch/s390/mm/fault.c | 66 ++++++++++-------------
arch/x86/mm/fault.c | 55 ++++++++-----------
include/linux/mm.h | 17 ++++++
include/linux/mm_types.h | 2 +
mm/memory.c | 39 ++++++++++++++
12 files changed, 278 insertions(+), 233 deletions(-)
--
2.27.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Kefeng Wang <hidden> Date: 2023-08-21 12:31:20
The ARCH_SUPPORTS_PER_VMA_LOCK are enabled by more and more architectures,
eg, x86, arm64, powerpc and s390, and riscv, those implementation are very
similar which results in some duplicated codes, let's add a generic VMA
lock-based page fault handler try_to_vma_locked_page_fault() to eliminate
them, and which also make us easy to support this on new architectures.
Since different architectures use different way to check vma whether is
accessable or not, the struct pt_regs, page fault error code and vma flags
are added into struct vm_fault, then, the architecture's page fault code
could re-use struct vm_fault to record and check vma accessable by each
own implementation.
Signed-off-by: Kefeng Wang <redacted>
---
include/linux/mm.h | 17 +++++++++++++++++
include/linux/mm_types.h | 2 ++
mm/memory.c | 39 +++++++++++++++++++++++++++++++++++++++
3 files changed, 58 insertions(+)
From: Kefeng Wang <hidden> Date: 2023-08-21 12:31:23
Use new try_vma_locked_page_fault() helper to simplify code, also
pass struct vmf to __do_page_fault() directly instead of each
independent variable. No functional change intended.
Signed-off-by: Kefeng Wang <redacted>
---
arch/arm64/mm/fault.c | 60 ++++++++++++++++---------------------------
1 file changed, 22 insertions(+), 38 deletions(-)
@@ -533,10 +532,12 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,conststructfault_info*inf;structmm_struct*mm=current->mm;vm_fault_tfault;-unsignedlongvm_flags;-unsignedintmm_flags=FAULT_FLAG_DEFAULT;unsignedlongaddr=untagged_addr(far);structvm_area_struct*vma;+structvm_faultvmf={+.real_address=addr,+.flags=FAULT_FLAG_DEFAULT,+};if(kprobe_page_fault(regs,esr))return0;
@@ -549,7 +550,7 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,gotono_context;if(user_mode(regs))-mm_flags|=FAULT_FLAG_USER;+vmf.flags|=FAULT_FLAG_USER;/**vm_flagstellsuswhatbitswemusthaveinvma->vm_flags
@@ -559,20 +560,20 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,*/if(is_el0_instruction_abort(esr)){/* It was exec fault */-vm_flags=VM_EXEC;-mm_flags|=FAULT_FLAG_INSTRUCTION;+vmf.vm_flags=VM_EXEC;+vmf.flags|=FAULT_FLAG_INSTRUCTION;}elseif(is_write_abort(esr)){/* It was write fault */-vm_flags=VM_WRITE;-mm_flags|=FAULT_FLAG_WRITE;+vmf.vm_flags=VM_WRITE;+vmf.flags|=FAULT_FLAG_WRITE;}else{/* It was read fault */-vm_flags=VM_READ;+vmf.vm_flags=VM_READ;/* Write implies read */-vm_flags|=VM_WRITE;+vmf.vm_flags|=VM_WRITE;/* If EPAN is absent then exec implies read */if(!cpus_have_const_cap(ARM64_HAS_EPAN))-vm_flags|=VM_EXEC;+vmf.vm_flags|=VM_EXEC;}if(is_ttbr0_addr(addr)&&is_el1_permission_fault(addr,esr,regs)){
@@ -587,26 +588,11 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS,1,regs,addr);-if(!(mm_flags&FAULT_FLAG_USER))-gotolock_mmap;--vma=lock_vma_under_rcu(mm,addr);-if(!vma)-gotolock_mmap;--if(!(vma->vm_flags&vm_flags)){-vma_end_read(vma);-gotolock_mmap;-}-fault=handle_mm_fault(vma,addr,mm_flags|FAULT_FLAG_VMA_LOCK,regs);-if(!(fault&(VM_FAULT_RETRY|VM_FAULT_COMPLETED)))-vma_end_read(vma);--if(!(fault&VM_FAULT_RETRY)){-count_vm_vma_lock_event(VMA_LOCK_SUCCESS);+fault=try_vma_locked_page_fault(&vmf);+if(fault==VM_FAULT_NONE)+gotoretry;+if(!(fault&VM_FAULT_RETRY))gotodone;-}-count_vm_vma_lock_event(VMA_LOCK_RETRY);/* Quick path to respond to signals */if(fault_signal_pending(fault,regs)){
@@ -614,8 +600,6 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,gotono_context;return0;}-lock_mmap:-retry:vma=lock_mm_and_find_vma(mm,addr,regs);if(unlikely(!vma)){
@@ -623,7 +607,7 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,gotodone;}-fault=__do_page_fault(mm,vma,addr,mm_flags,vm_flags,regs);+fault=__do_page_fault(mm,vma,&vmf);/* Quick path to respond to signals */if(fault_signal_pending(fault,regs)){
@@ -637,7 +621,7 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,return0;if(fault&VM_FAULT_RETRY){-mm_flags|=FAULT_FLAG_TRIED;+vmf.flags|=FAULT_FLAG_TRIED;gotoretry;}mmap_read_unlock(mm);
--
2.27.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
@@ -391,6 +391,22 @@ static int page_fault_is_bad(unsigned long err)#define page_fault_is_bad(__err) ((__err) & DSISR_BAD_FAULT_32S)#endif+#ifdef CONFIG_PER_VMA_LOCK+boolarch_vma_access_error(structvm_area_struct*vma,structvm_fault*vmf)+{+intis_exec=TRAP(vmf->regs)==INTERRUPT_INST_STORAGE;+intis_write=page_fault_is_write(vmf->fault_code);++if(unlikely(access_pkey_error(is_write,is_exec,+(vmf->fault_code&DSISR_KEYFAULT),vma)))+returntrue;++if(unlikely(access_error(is_write,is_exec,vma)))+returntrue;+returnfalse;+}+#endif+/**For600-and800-familyprocessors,theerror_codeparameterisDSISR*foradatafault,SRR1foraninstructionfault.
@@ -407,12 +423,18 @@ static int ___do_page_fault(struct pt_regs *regs, unsigned long address,{structvm_area_struct*vma;structmm_struct*mm=current->mm;-unsignedintflags=FAULT_FLAG_DEFAULT;intis_exec=TRAP(regs)==INTERRUPT_INST_STORAGE;intis_user=user_mode(regs);intis_write=page_fault_is_write(error_code);vm_fault_tfault,major=0;boolkprobe_fault=kprobe_page_fault(regs,11);+structvm_faultvmf={+.real_address=address,+.fault_code=error_code,+.regs=regs,+.flags=FAULT_FLAG_DEFAULT,+};+if(unlikely(debugger_fault_handler(regs)||kprobe_fault))return0;
@@ -463,45 +485,21 @@ static int ___do_page_fault(struct pt_regs *regs, unsigned long address,*mmap_lockheld*/if(is_user)-flags|=FAULT_FLAG_USER;+vmf.flags|=FAULT_FLAG_USER;if(is_write)-flags|=FAULT_FLAG_WRITE;+vmf.flags|=FAULT_FLAG_WRITE;if(is_exec)-flags|=FAULT_FLAG_INSTRUCTION;+vmf.flags|=FAULT_FLAG_INSTRUCTION;-if(!(flags&FAULT_FLAG_USER))-gotolock_mmap;--vma=lock_vma_under_rcu(mm,address);-if(!vma)-gotolock_mmap;--if(unlikely(access_pkey_error(is_write,is_exec,-(error_code&DSISR_KEYFAULT),vma))){-vma_end_read(vma);-gotolock_mmap;-}--if(unlikely(access_error(is_write,is_exec,vma))){-vma_end_read(vma);-gotolock_mmap;-}--fault=handle_mm_fault(vma,address,flags|FAULT_FLAG_VMA_LOCK,regs);-if(!(fault&(VM_FAULT_RETRY|VM_FAULT_COMPLETED)))-vma_end_read(vma);--if(!(fault&VM_FAULT_RETRY)){-count_vm_vma_lock_event(VMA_LOCK_SUCCESS);+fault=try_vma_locked_page_fault(&vmf);+if(fault==VM_FAULT_NONE)+gotoretry;+if(!(fault&VM_FAULT_RETRY))gotodone;-}-count_vm_vma_lock_event(VMA_LOCK_RETRY);if(fault_signal_pending(fault,regs))returnuser_mode(regs)?0:SIGBUS;-lock_mmap:-/* When running in the kernel we expect faults to occur only to*addressesinuserspace.Allotherfaultsrepresenterrorsinthe*kernelandshouldgenerateanOOPS.Unfortunately,inthecaseofan
@@ -528,7 +526,7 @@ static int ___do_page_fault(struct pt_regs *regs, unsigned long address,*makesureweexitgracefullyratherthanendlesslyredo*thefault.*/-fault=handle_mm_fault(vma,address,flags,regs);+fault=handle_mm_fault(vma,address,vmf.flags,regs);major|=fault&VM_FAULT_MAJOR;
@@ -544,7 +542,7 @@ static int ___do_page_fault(struct pt_regs *regs, unsigned long address,*case.*/if(unlikely(fault&VM_FAULT_RETRY)){-flags|=FAULT_FLAG_TRIED;+vmf.flags|=FAULT_FLAG_TRIED;gotoretry;}
--
2.27.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Kefeng Wang <hidden> Date: 2023-08-21 12:31:33
Attempt VMA lock-based page fault handling first, and fall back
to the existing mmap_lock-based handling if that fails.
Signed-off-by: Kefeng Wang <redacted>
---
arch/arm/Kconfig | 1 +
arch/arm/mm/fault.c | 35 +++++++++++++++++++++++++----------
2 files changed, 26 insertions(+), 10 deletions(-)
@@ -242,8 +242,11 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)structvm_area_struct*vma;intsig,code;vm_fault_tfault;-unsignedintflags=FAULT_FLAG_DEFAULT;-unsignedlongvm_flags=VM_ACCESS_FLAGS;+structvm_faultvmf={+.real_address=addr,+.flags=FAULT_FLAG_DEFAULT,+.vm_flags=VM_ACCESS_FLAGS,+};if(kprobe_page_fault(regs,fsr))return0;
@@ -261,15 +264,15 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)gotono_context;if(user_mode(regs))-flags|=FAULT_FLAG_USER;+vmf.flags|=FAULT_FLAG_USER;if(is_write_fault(fsr)){-flags|=FAULT_FLAG_WRITE;-vm_flags=VM_WRITE;+vmf.flags|=FAULT_FLAG_WRITE;+vmf.vm_flags=VM_WRITE;}if(fsr&FSR_LNX_PF){-vm_flags=VM_EXEC;+vmf.vm_flags=VM_EXEC;if(is_permission_fault(fsr)&&!user_mode(regs))die_kernel_fault("execution of memory",
@@ -278,6 +281,18 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS,1,regs,addr);+fault=try_vma_locked_page_fault(&vmf);+if(fault==VM_FAULT_NONE)+gotoretry;+if(!(fault&VM_FAULT_RETRY))+gotodone;++if(fault_signal_pending(fault,regs)){+if(!user_mode(regs))+gotono_context;+return0;+}+retry:vma=lock_mm_and_find_vma(mm,addr,regs);if(unlikely(!vma)){
@@ -289,10 +304,10 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)*ok,wehaveagoodvm_areaforthismemoryaccess,checkthe*permissionsontheVMAallowforthefaultwhichoccurred.*/-if(!(vma->vm_flags&vm_flags))+if(!(vma->vm_flags&vmf.vm_flags))fault=VM_FAULT_BADACCESS;else-fault=handle_mm_fault(vma,addr&PAGE_MASK,flags,regs);+fault=handle_mm_fault(vma,addr&PAGE_MASK,vmf.flags,regs);/* If we need to retry but a fatal signal is pending, handle the*signalfirst.Wedonotneedtoreleasethemmap_lockbecause
@@ -310,13 +325,13 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)if(!(fault&VM_FAULT_ERROR)){if(fault&VM_FAULT_RETRY){-flags|=FAULT_FLAG_TRIED;+vmf.flags|=FAULT_FLAG_TRIED;gotoretry;}}mmap_read_unlock(mm);-+done:/**Handlethe"normal"casefirst-VM_FAULT_MAJOR*/
--
2.27.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Kefeng Wang <hidden> Date: 2023-08-21 12:31:37
Add access_error() to check whether vma could be accessible or not,
which will be used __do_page_fault() and later vma locked based page
fault.
Signed-off-by: Kefeng Wang <redacted>
---
arch/loongarch/mm/fault.c | 30 ++++++++++++++++++++----------
1 file changed, 20 insertions(+), 10 deletions(-)
From: Kefeng Wang <hidden> Date: 2023-08-21 12:31:41
Attempt VMA lock-based page fault handling first, and fall back
to the existing mmap_lock-based handling if that fails.
Signed-off-by: Kefeng Wang <redacted>
---
arch/loongarch/Kconfig | 1 +
arch/loongarch/mm/fault.c | 37 +++++++++++++++++++++++++++++++------
2 files changed, 32 insertions(+), 6 deletions(-)
Use new try_vma_locked_page_fault() helper to simplify code.
No functional change intended.
Does it really simplifies code ? It's 32 insertions versus 34 deletions
so only removing 2 lines.
I don't like the struct vm_fault you are adding because when it was four
independant variables it was handled through local registers. Now that
it is a struct it has to go via the stack, leading to unnecessary memory
read and writes. And going back and forth between architecture code and
generic code may also be counter-performant.
Did you make any performance analysis ? Page faults are really a hot
path when dealling with minor faults.
Thanks
Christophe
@@ -391,6 +391,22 @@ static int page_fault_is_bad(unsigned long err)#define page_fault_is_bad(__err) ((__err) & DSISR_BAD_FAULT_32S)#endif+#ifdef CONFIG_PER_VMA_LOCK+boolarch_vma_access_error(structvm_area_struct*vma,structvm_fault*vmf)+{+intis_exec=TRAP(vmf->regs)==INTERRUPT_INST_STORAGE;+intis_write=page_fault_is_write(vmf->fault_code);++if(unlikely(access_pkey_error(is_write,is_exec,+(vmf->fault_code&DSISR_KEYFAULT),vma)))+returntrue;++if(unlikely(access_error(is_write,is_exec,vma)))+returntrue;+returnfalse;+}+#endif+/**For600-and800-familyprocessors,theerror_codeparameterisDSISR*foradatafault,SRR1foraninstructionfault.
@@ -407,12 +423,18 @@ static int ___do_page_fault(struct pt_regs *regs, unsigned long address,{structvm_area_struct*vma;structmm_struct*mm=current->mm;-unsignedintflags=FAULT_FLAG_DEFAULT;intis_exec=TRAP(regs)==INTERRUPT_INST_STORAGE;intis_user=user_mode(regs);intis_write=page_fault_is_write(error_code);vm_fault_tfault,major=0;boolkprobe_fault=kprobe_page_fault(regs,11);+structvm_faultvmf={+.real_address=address,+.fault_code=error_code,+.regs=regs,+.flags=FAULT_FLAG_DEFAULT,+};+if(unlikely(debugger_fault_handler(regs)||kprobe_fault))return0;
@@ -463,45 +485,21 @@ static int ___do_page_fault(struct pt_regs *regs, unsigned long address,*mmap_lockheld*/if(is_user)-flags|=FAULT_FLAG_USER;+vmf.flags|=FAULT_FLAG_USER;if(is_write)-flags|=FAULT_FLAG_WRITE;+vmf.flags|=FAULT_FLAG_WRITE;if(is_exec)-flags|=FAULT_FLAG_INSTRUCTION;+vmf.flags|=FAULT_FLAG_INSTRUCTION;-if(!(flags&FAULT_FLAG_USER))-gotolock_mmap;--vma=lock_vma_under_rcu(mm,address);-if(!vma)-gotolock_mmap;--if(unlikely(access_pkey_error(is_write,is_exec,-(error_code&DSISR_KEYFAULT),vma))){-vma_end_read(vma);-gotolock_mmap;-}--if(unlikely(access_error(is_write,is_exec,vma))){-vma_end_read(vma);-gotolock_mmap;-}--fault=handle_mm_fault(vma,address,flags|FAULT_FLAG_VMA_LOCK,regs);-if(!(fault&(VM_FAULT_RETRY|VM_FAULT_COMPLETED)))-vma_end_read(vma);--if(!(fault&VM_FAULT_RETRY)){-count_vm_vma_lock_event(VMA_LOCK_SUCCESS);+fault=try_vma_locked_page_fault(&vmf);+if(fault==VM_FAULT_NONE)+gotoretry;+if(!(fault&VM_FAULT_RETRY))gotodone;-}-count_vm_vma_lock_event(VMA_LOCK_RETRY);if(fault_signal_pending(fault,regs))returnuser_mode(regs)?0:SIGBUS;-lock_mmap:-/* When running in the kernel we expect faults to occur only to*addressesinuserspace.Allotherfaultsrepresenterrorsinthe*kernelandshouldgenerateanOOPS.Unfortunately,inthecaseofan
@@ -528,7 +526,7 @@ static int ___do_page_fault(struct pt_regs *regs, unsigned long address,*makesureweexitgracefullyratherthanendlesslyredo*thefault.*/-fault=handle_mm_fault(vma,address,flags,regs);+fault=handle_mm_fault(vma,address,vmf.flags,regs);major|=fault&VM_FAULT_MAJOR;
@@ -544,7 +542,7 @@ static int ___do_page_fault(struct pt_regs *regs, unsigned long address,*case.*/if(unlikely(fault&VM_FAULT_RETRY)){-flags|=FAULT_FLAG_TRIED;+vmf.flags|=FAULT_FLAG_TRIED;gotoretry;}
From: Kefeng Wang <hidden> Date: 2023-08-22 12:13:03
On 2023/8/22 17:38, Christophe Leroy wrote:
Le 21/08/2023 à 14:30, Kefeng Wang a écrit :
quoted
Use new try_vma_locked_page_fault() helper to simplify code.
No functional change intended.
Does it really simplifies code ? It's 32 insertions versus 34 deletions
so only removing 2 lines.
Yes,it is unfriendly for powerpc as the arch's vma access check is much
complex than other arch,
I don't like the struct vm_fault you are adding because when it was four
independant variables it was handled through local registers. Now that
it is a struct it has to go via the stack, leading to unnecessary memory
read and writes. And going back and forth between architecture code and
generic code may also be counter-performant.
Because different arch has different var to check vma access, so the
easy way to add them into vmf, I don' find a better way.
Did you make any performance analysis ? Page faults are really a hot
path when dealling with minor faults.
no, this is only built and rfc to see the feedback about the conversion.
Thanks.
@@ -391,6 +391,22 @@ static int page_fault_is_bad(unsigned long err)#define page_fault_is_bad(__err) ((__err) & DSISR_BAD_FAULT_32S)#endif+#ifdef CONFIG_PER_VMA_LOCK+boolarch_vma_access_error(structvm_area_struct*vma,structvm_fault*vmf)+{+intis_exec=TRAP(vmf->regs)==INTERRUPT_INST_STORAGE;+intis_write=page_fault_is_write(vmf->fault_code);++if(unlikely(access_pkey_error(is_write,is_exec,+(vmf->fault_code&DSISR_KEYFAULT),vma)))+returntrue;++if(unlikely(access_error(is_write,is_exec,vma)))+returntrue;+returnfalse;+}+#endif+/**For600-and800-familyprocessors,theerror_codeparameterisDSISR*foradatafault,SRR1foraninstructionfault.
@@ -407,12 +423,18 @@ static int ___do_page_fault(struct pt_regs *regs, unsigned long address,{structvm_area_struct*vma;structmm_struct*mm=current->mm;-unsignedintflags=FAULT_FLAG_DEFAULT;intis_exec=TRAP(regs)==INTERRUPT_INST_STORAGE;intis_user=user_mode(regs);intis_write=page_fault_is_write(error_code);vm_fault_tfault,major=0;boolkprobe_fault=kprobe_page_fault(regs,11);+structvm_faultvmf={+.real_address=address,+.fault_code=error_code,+.regs=regs,+.flags=FAULT_FLAG_DEFAULT,+};+if(unlikely(debugger_fault_handler(regs)||kprobe_fault))return0;
@@ -463,45 +485,21 @@ static int ___do_page_fault(struct pt_regs *regs, unsigned long address,*mmap_lockheld*/if(is_user)-flags|=FAULT_FLAG_USER;+vmf.flags|=FAULT_FLAG_USER;if(is_write)-flags|=FAULT_FLAG_WRITE;+vmf.flags|=FAULT_FLAG_WRITE;if(is_exec)-flags|=FAULT_FLAG_INSTRUCTION;+vmf.flags|=FAULT_FLAG_INSTRUCTION;-if(!(flags&FAULT_FLAG_USER))-gotolock_mmap;--vma=lock_vma_under_rcu(mm,address);-if(!vma)-gotolock_mmap;--if(unlikely(access_pkey_error(is_write,is_exec,-(error_code&DSISR_KEYFAULT),vma))){-vma_end_read(vma);-gotolock_mmap;-}--if(unlikely(access_error(is_write,is_exec,vma))){-vma_end_read(vma);-gotolock_mmap;-}--fault=handle_mm_fault(vma,address,flags|FAULT_FLAG_VMA_LOCK,regs);-if(!(fault&(VM_FAULT_RETRY|VM_FAULT_COMPLETED)))-vma_end_read(vma);--if(!(fault&VM_FAULT_RETRY)){-count_vm_vma_lock_event(VMA_LOCK_SUCCESS);+fault=try_vma_locked_page_fault(&vmf);+if(fault==VM_FAULT_NONE)+gotoretry;+if(!(fault&VM_FAULT_RETRY))gotodone;-}-count_vm_vma_lock_event(VMA_LOCK_RETRY);if(fault_signal_pending(fault,regs))returnuser_mode(regs)?0:SIGBUS;-lock_mmap:-/* When running in the kernel we expect faults to occur only to*addressesinuserspace.Allotherfaultsrepresenterrorsinthe*kernelandshouldgenerateanOOPS.Unfortunately,inthecaseofan
@@ -528,7 +526,7 @@ static int ___do_page_fault(struct pt_regs *regs, unsigned long address,*makesureweexitgracefullyratherthanendlesslyredo*thefault.*/-fault=handle_mm_fault(vma,address,flags,regs);+fault=handle_mm_fault(vma,address,vmf.flags,regs);major|=fault&VM_FAULT_MAJOR;
@@ -544,7 +542,7 @@ static int ___do_page_fault(struct pt_regs *regs, unsigned long address,*case.*/if(unlikely(fault&VM_FAULT_RETRY)){-flags|=FAULT_FLAG_TRIED;+vmf.flags|=FAULT_FLAG_TRIED;gotoretry;}
From: Alexander Gordeev <agordeev@linux.ibm.com> Date: 2023-08-24 07:14:54
On Mon, Aug 21, 2023 at 08:30:47PM +0800, Kefeng Wang wrote:
Hi Kefeng,
quoted hunk
The ARCH_SUPPORTS_PER_VMA_LOCK are enabled by more and more architectures,
eg, x86, arm64, powerpc and s390, and riscv, those implementation are very
similar which results in some duplicated codes, let's add a generic VMA
lock-based page fault handler try_to_vma_locked_page_fault() to eliminate
them, and which also make us easy to support this on new architectures.
Since different architectures use different way to check vma whether is
accessable or not, the struct pt_regs, page fault error code and vma flags
are added into struct vm_fault, then, the architecture's page fault code
could re-use struct vm_fault to record and check vma accessable by each
own implementation.
Signed-off-by: Kefeng Wang <redacted>
---
include/linux/mm.h | 17 +++++++++++++++++
include/linux/mm_types.h | 2 ++
mm/memory.c | 39 +++++++++++++++++++++++++++++++++++++++
3 files changed, 58 insertions(+)
Because VM_FAULT_NONE is set to 0 it gets confused with
the success code of 0 returned by a fault handler. In the
former case we want to continue, while in the latter -
successfully return. I think it applies to all archs.
@@ -466,7 +454,7 @@ static inline vm_fault_t do_exception(struct pt_regs *regs, int access) * we can handle it.. */ fault = VM_FAULT_BADACCESS;- if (unlikely(!(vma->vm_flags & access)))+ if (unlikely(!(vma->vm_flags & vmf.vm_flags))) goto out_up; /*
@@ -474,10 +462,10 @@ static inline vm_fault_t do_exception(struct pt_regs *regs, int access) * make sure we exit gracefully rather than endlessly redo * the fault. */- fault = handle_mm_fault(vma, address, flags, regs);+ fault = handle_mm_fault(vma, address, vmf.flags, regs); if (fault_signal_pending(fault, regs)) { fault = VM_FAULT_SIGNAL;- if (flags & FAULT_FLAG_RETRY_NOWAIT)+ if (vmf.flags & FAULT_FLAG_RETRY_NOWAIT) goto out_up; goto out; }
@@ -497,7 +485,7 @@ static inline vm_fault_t do_exception(struct pt_regs *regs, int access) if (fault & VM_FAULT_RETRY) { if (IS_ENABLED(CONFIG_PGSTE) && gmap &&- (flags & FAULT_FLAG_RETRY_NOWAIT)) {+ (vmf.flags & FAULT_FLAG_RETRY_NOWAIT)) { /* * FAULT_FLAG_RETRY_NOWAIT has been set, mmap_lock has * not been released
FWIW, this series ends up with kernel BUG at arch/s390/mm/fault.c:341!
Thanks!
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Because VM_FAULT_NONE is set to 0 it gets confused with
the success code of 0 returned by a fault handler. In the
former case we want to continue, while in the latter -
successfully return. I think it applies to all archs.
...
FWIW, this series ends up with kernel BUG at arch/s390/mm/fault.c:341!
Without having looked in detail into this patch: all of this is likely
because s390's fault handling is quite odd. Not only because fault is set
to 0, but also because of the private VM_FAULT values like
VM_FAULT_BADCONTEXT. I'm just cleaning up all of this, but it won't make it
for the next merge window.
Therefore I'd like to ask to drop the s390 conversion of this series, and
if this series is supposed to be merged the s390 conversion needs to be
done later. Let's not waste more time on the current implementation,
please.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Kefeng Wang <hidden> Date: 2023-08-26 00:57:20
On 2023/8/24 15:12, Alexander Gordeev wrote:
On Mon, Aug 21, 2023 at 08:30:47PM +0800, Kefeng Wang wrote:
Hi Kefeng,
quoted
The ARCH_SUPPORTS_PER_VMA_LOCK are enabled by more and more architectures,
eg, x86, arm64, powerpc and s390, and riscv, those implementation are very
similar which results in some duplicated codes, let's add a generic VMA
lock-based page fault handler try_to_vma_locked_page_fault() to eliminate
them, and which also make us easy to support this on new architectures.
Since different architectures use different way to check vma whether is
accessable or not, the struct pt_regs, page fault error code and vma flags
are added into struct vm_fault, then, the architecture's page fault code
could re-use struct vm_fault to record and check vma accessable by each
own implementation.
Signed-off-by: Kefeng Wang <redacted>
---
Because VM_FAULT_NONE is set to 0 it gets confused with
the success code of 0 returned by a fault handler. In the
former case we want to continue, while in the latter -
successfully return. I think it applies to all archs.
...
quoted
FWIW, this series ends up with kernel BUG at arch/s390/mm/fault.c:341!
I didn't test and only built, this is a RFC to want to know whether
the way to add three more numbers into vmf and using vmf in arch's page
fault is feasible or not.
Without having looked in detail into this patch: all of this is likely
because s390's fault handling is quite odd. Not only because fault is set
to 0, but also because of the private VM_FAULT values like
VM_FAULT_BADCONTEXT. I'm just cleaning up all of this, but it won't make it
for the next merge window.
Sure, if re-post, will drop the s390's change, but as mentioned above,
the abstract of the generic vma locked and changes may be not perfect,
let's wait for more response.
Thanks all.
Therefore I'd like to ask to drop the s390 conversion of this series, and
if this series is supposed to be merged the s390 conversion needs to be
done later. Let's not waste more time on the current implementation,
please.