Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/x86/x86 - pmap_enter(): under low memory conditions...
details: https://anonhg.NetBSD.org/src/rev/a5b425e40aa4
branches: trunk
changeset: 745957:a5b425e40aa4
user: ad <ad%NetBSD.org@localhost>
date: Tue Mar 17 22:37:05 2020 +0000
description:
- pmap_enter(): under low memory conditions, if PTP allocation succeeded and
then PV entry allocation failed, PTP pages were being freed without their
struct pmap_page being reset back to the non-PTP setup, which then caused
havoc with pmap_page_removed(). Fix it.
- pmap_enter_pv(): don't do the PV check if memory allocation failed.
Reported-by: syzbot+d9b42238107c155ca0cd%syzkaller.appspotmail.com@localhost
Reported-by: syzbot+80cf4850dc1cf29901dc%syzkaller.appspotmail.com@localhost
diffstat:
sys/arch/x86/x86/pmap.c | 61 +++++++++++++-----------------------------------
1 files changed, 17 insertions(+), 44 deletions(-)
diffs (136 lines):
diff -r ebcfc7d9f157 -r a5b425e40aa4 sys/arch/x86/x86/pmap.c
--- a/sys/arch/x86/x86/pmap.c Tue Mar 17 22:29:19 2020 +0000
+++ b/sys/arch/x86/x86/pmap.c Tue Mar 17 22:37:05 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.c,v 1.374 2020/03/17 22:29:19 ad Exp $ */
+/* $NetBSD: pmap.c,v 1.375 2020/03/17 22:37:05 ad Exp $ */
/*
* Copyright (c) 2008, 2010, 2016, 2017, 2019, 2020 The NetBSD Foundation, Inc.
@@ -130,7 +130,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.374 2020/03/17 22:29:19 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.375 2020/03/17 22:37:05 ad Exp $");
#include "opt_user_ldt.h"
#include "opt_lockdebug.h"
@@ -635,30 +635,6 @@
}
/*
- * pmap_ptp_init: initialize new page table page
- */
-static inline void
-pmap_ptp_init(struct vm_page *ptp)
-{
-
- ptp->uanon = (struct vm_anon *)(vaddr_t)~0L;
- rb_tree_init(&VM_PAGE_TO_PP(ptp)->pp_rb, &pmap_rbtree_ops);
- PMAP_CHECK_PP(VM_PAGE_TO_PP(ptp));
-}
-
-/*
- * pmap_ptp_fini: finalize a page table page
- */
-static inline void
-pmap_ptp_fini(struct vm_page *ptp)
-{
-
- KASSERT(RB_TREE_MIN(&VM_PAGE_TO_PP(ptp)->pp_rb) == NULL);
- PMAP_CHECK_PP(VM_PAGE_TO_PP(ptp));
- ptp->uanon = NULL;
-}
-
-/*
* pmap_ptp_range_set: abuse ptp->uanon to record minimum VA of PTE
*/
static inline void
@@ -2158,7 +2134,9 @@
LIST_INSERT_HEAD(&pp->pp_pvlist, pve, pve_list);
}
mutex_spin_exit(&pp->pp_lock);
- pmap_check_pv(pmap, ptp, pp, va, true);
+ if (error == 0) {
+ pmap_check_pv(pmap, ptp, pp, va, true);
+ }
return error;
}
@@ -2252,13 +2230,15 @@
int lidx;
KASSERT(ptp->wire_count == 1);
+ PMAP_CHECK_PP(VM_PAGE_TO_PP(ptp));
lidx = level - 1;
pmap_stats_update(pmap, -1, 0);
if (pmap->pm_ptphint[lidx] == ptp)
pmap->pm_ptphint[lidx] = NULL;
ptp->wire_count = 0;
- pmap_ptp_fini(ptp);
+ ptp->uanon = NULL;
+ KASSERT(RB_TREE_MIN(&VM_PAGE_TO_PP(ptp)->pp_rb) == NULL);
/*
* Enqueue the PTP to be freed by pmap_update(). We can't remove
@@ -2357,19 +2337,21 @@
if (pt->pg[i] == NULL) {
pt->pg[i] = uvm_pagealloc(obj, off, NULL, aflags);
- pt->alloced[i] = true;
- if (pt->pg[i] != NULL) {
- pmap_ptp_init(pt->pg[i]);
- }
+ pt->alloced[i] = (pt->pg[i] != NULL);
} else if (pt->pg[i]->wire_count == 0) {
/* This page was queued to be freed; dequeue it. */
LIST_REMOVE(pt->pg[i], mdpage.mp_pp.pp_link);
- pmap_ptp_init(pt->pg[i]);
+ pt->alloced[i] = true;
}
PMAP_DUMMY_UNLOCK(pmap);
if (pt->pg[i] == NULL) {
pmap_unget_ptp(pmap, pt);
return ENOMEM;
+ } else {
+ pt->pg[i]->uanon = (struct vm_anon *)(vaddr_t)~0L;
+ rb_tree_init(&VM_PAGE_TO_PP(pt->pg[i])->pp_rb,
+ &pmap_rbtree_ops);
+ PMAP_CHECK_PP(VM_PAGE_TO_PP(pt->pg[i]));
}
}
ptp = pt->pg[2];
@@ -2464,22 +2446,12 @@
KASSERT(mutex_owned(&pmap->pm_lock));
for (i = PTP_LEVELS; i > 1; i--) {
- if (pt->pg[i] == NULL) {
- break;
- }
if (!pt->alloced[i]) {
continue;
}
KASSERT(pt->pg[i]->wire_count == 0);
PMAP_CHECK_PP(VM_PAGE_TO_PP(pt->pg[i]));
- /* pmap zeros all pages before freeing. */
- pt->pg[i]->flags |= PG_ZERO;
- pmap_ptp_fini(pt->pg[i]);
- PMAP_DUMMY_LOCK(pmap);
- uvm_pagefree(pt->pg[i]);
- PMAP_DUMMY_UNLOCK(pmap);
- pt->pg[i] = NULL;
- pmap->pm_ptphint[0] = NULL;
+ pmap_freepage(pmap, pt->pg[i], i - 1);
}
}
@@ -5232,6 +5204,7 @@
mutex_enter(&pmap->pm_lock);
while ((ptp = LIST_FIRST(&pmap->pm_gc_ptp)) != NULL) {
KASSERT(ptp->wire_count == 0);
+ KASSERT(ptp->uanon == NULL);
LIST_REMOVE(ptp, mdpage.mp_pp.pp_link);
pp = VM_PAGE_TO_PP(ptp);
LIST_INIT(&pp->pp_pvlist);
Home |
Main Index |
Thread Index |
Old Index