NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
port-arm/58135: reproducible pmap KASSERT failure for armv7 with NFS root
>Number: 58135
>Category: port-arm
>Synopsis: reproducible pmap KASSERT failure for armv7 with NFS root
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: port-arm-maintainer
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Wed Apr 10 03:35:00 +0000 2024
>Originator: Rin Okuyama
>Release: 10.99.10 and 10.0
>Organization:
Internet Initiative Japan Inc.
>Environment:
NetBSD console 10.99.10 NetBSD 10.99.10 (SUNXI_NET_MPSAFE) #1: Thu Feb 8 23:00:33 JST 2024 rin@sakaizumii.local:/home/rin/src/sys/arch/evbarm/compile/SUNXI_NET_MPSAFE evbarm earmv7hfeb
>Description:
Running armv7-based system with NFS root, KASSERT failure for
pmap can be easily triggered for few hours. For example:
$ cd /usr/pkgsrc/lang/perl5 && make install
...
Finding dependencies for av.o
[ 28405.9114372] panic: kernel diagnostic assertion "(((uintptr_t)ptep / sizeof(pte)) & (L2_L_SIZE / L2_S_SIZE - 1)) == 0" failed: file "./arm/arm32/pmap.h", line 603 0x90061930
[ 28405.9114372] cpu0: Begin traceback...
[ 28405.9114372] 0xa876fbac: netbsd:db_panic+0x14
[ 28405.9114372] 0xa876fbcc: netbsd:vpanic+0x114
[ 28405.9114372] 0xa876fbe4: netbsd:kern_assert+0x40
[ 28405.9114372] 0xa876fc6c: netbsd:pmap_clearbit+0x490
[ 28405.9114372] 0xa876fc84: netbsd:pmap_page_protect+0x78
[ 28405.9114372] 0xa876fcac: netbsd:nfs_gop_write+0x48
[ 28405.9114372] 0xa876fe1c: netbsd:genfs_do_putpages+0x7b8
[ 28405.9114372] 0xa876fe44: netbsd:genfs_putpages+0x34
[ 28405.9114372] 0xa876fe7c: netbsd:VOP_PUTPAGES+0x78
[ 28405.9114372] 0xa876fea4: netbsd:nfs_fsync+0x60
[ 28405.9114372] 0xa876fedc: netbsd:VOP_FSYNC+0x7c
[ 28405.9114372] 0xa876ff24: netbsd:nfs_sync+0x80
[ 28405.9114372] 0xa876ff44: netbsd:VFS_SYNC+0x3c
[ 28405.9114372] 0xa876ffac: netbsd:sched_sync+0xdc
[ 28405.9114372] cpu0: End traceback...
This takes place both for -current and 10.0.
I've found this can be explained as follows:
(1) nfs_gop_write() unconditionally calls pmap_page_protect:
280 for (i = 0; i < npages; i++) {
281 pmap_page_protect(pgs[i], VM_PROT_READ);
282 }
https://nxr.netbsd.org/xref/src/sys/nfs/nfs_node.c#281
and
(2) pmap_clearbit() turns on L2_XS_XN == __BIT(0) without checking
the target page is valid (i.e., L2_TYPE_S == __BIT(1) is turned on):
2326 static void
2327 pmap_clearbit(struct vm_page_md *md, paddr_t pa, u_int maskbits)
2328 {
...
2333 #ifdef ARM_MMU_EXTENDED
2334 const u_int execbits = (maskbits & PVF_EXEC) ? L2_XS_XN : 0;
2335 #else
...
2422 pt_entry_t * const ptep = &l2b->l2b_kva[l2pte_index(va)];
2423 const pt_entry_t opte = *ptep;
2424 pt_entry_t npte = opte | execbits;
https://nxr.netbsd.org/xref/src/sys/arch/arm/arm32/pmap.c#2334
https://nxr.netbsd.org/xref/src/sys/arch/arm/arm32/pmap.c#2424
L2_XS_XN is regarded as L2_TYPE_L if L2_TYPE_S is cleared, which
results in the KASSERT above.
I'm not sure whether NFS code is optimal, but (2) should be fixed
anyway.
>How-To-Repeat:
Boot armv7 system with NFS root, and build some pkgsrc.
>Fix:
Check page validity (as well as executability) before set L2_XS_XN:
diff --git a/sys/arch/arm/arm32/pmap.c b/sys/arch/arm/arm32/pmap.c
index 64797e18a0c..1305344be5f 100644
--- a/sys/arch/arm/arm32/pmap.c
+++ b/sys/arch/arm/arm32/pmap.c
@@ -2330,15 +2330,10 @@ pmap_clearbit(struct vm_page_md *md, paddr_t pa, u_int maskbits)
#ifdef PMAP_CACHE_VIPT
const bool want_syncicache = PV_IS_EXEC_P(md->pvh_attrs);
bool need_syncicache = false;
-#ifdef ARM_MMU_EXTENDED
- const u_int execbits = (maskbits & PVF_EXEC) ? L2_XS_XN : 0;
-#else
- const u_int execbits = 0;
+#ifndef ARM_MMU_EXTENDED
bool need_vac_me_harder = false;
#endif
-#else
- const u_int execbits = 0;
-#endif
+#endif /* PMAP_CACHE_VIPT */
UVMHIST_FUNC(__func__);
UVMHIST_CALLARGS(maphist, "md %#jx pa %#jx maskbits %#jx",
@@ -2421,7 +2416,14 @@ pmap_clearbit(struct vm_page_md *md, paddr_t pa, u_int maskbits)
pt_entry_t * const ptep = &l2b->l2b_kva[l2pte_index(va)];
const pt_entry_t opte = *ptep;
- pt_entry_t npte = opte | execbits;
+ pt_entry_t npte = opte;
+
+#if defined(ARM_MMU_EXTENDED) && defined(PMAP_CACHE_VIPT)
+ if ((maskbits & PVF_EXEC) != 0 && l2pte_valid_p(opte)) {
+ KASSERT((opte & L2_TYPE_S) != 0);
+ npte |= L2_XS_XN;
+ }
+#endif
#ifdef ARM_MMU_EXTENDED
KASSERT((opte & L2_XS_nG) == (pm == pmap_kernel() ? 0 : L2_XS_nG));
Home |
Main Index |
Thread Index |
Old Index