Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/sommerfeld_i386mp_1]: src/sys/arch/i386/i386 Fix from Frank van der Lind...
details: https://anonhg.NetBSD.org/src/rev/e0662d28d4cf
branches: sommerfeld_i386mp_1
changeset: 482470:e0662d28d4cf
user: sommerfeld <sommerfeld%NetBSD.org@localhost>
date: Sat Dec 29 20:59:22 2001 +0000
description:
Fix from Frank van der Linden to TLB shootdown:
"... both a 'flushu' (do a normal TLB flush, but not the PG_G entries)
and one or more PG_G entries could have been in the shootdown
queue. pmap_tlb_shootnow() would then only have done a plain tlb
flush, meaning that the PG_G address(es) on the shootdown queue
weren't handled.
"For this to happen you'd have to have 2 conditions: 1) the max. number
of items on the queue was exceeded, with only plain (user) entries
on the queue, and 2) after this event happened, a few PG_G entries were
added.
"This could triggered by an exec, which unmaps the whole process'
map, usually causing > 16 'plain' entries, and pmap_remove_ptes
wanting to free a pv page, causing a PG_G entry. The latter would
then not be flushed from the TLB."
Fix is to make we don't miss PG_G entries after a flushu.
diffstat:
sys/arch/i386/i386/pmap.c | 35 ++++++++++++++++++++++++++---------
1 files changed, 26 insertions(+), 9 deletions(-)
diffs (72 lines):
diff -r 9bba4e9d9b9c -r e0662d28d4cf sys/arch/i386/i386/pmap.c
--- a/sys/arch/i386/i386/pmap.c Sat Dec 29 18:19:31 2001 +0000
+++ b/sys/arch/i386/i386/pmap.c Sat Dec 29 20:59:22 2001 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: pmap.c,v 1.83.2.45 2001/09/22 23:07:29 sommerfeld Exp $ */
+/* $NetBSD: pmap.c,v 1.83.2.46 2001/12/29 20:59:22 sommerfeld Exp $ */
/*
*
@@ -59,6 +59,9 @@
* (NetBSD/alpha).
*/
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.83.2.46 2001/12/29 20:59:22 sommerfeld Exp $");
+
#include "opt_cputype.h"
#include "opt_user_ldt.h"
#include "opt_largepages.h"
@@ -3403,6 +3406,17 @@
pq = &pmap_tlb_shootdown_q[ci->ci_cpuid];
simple_lock(&pq->pq_slock);
+ /*
+ * If there's a global flush already queued, or a
+ * non-global flush, and this pte doesn't have the G
+ * bit set, don't bother.
+ */
+ if (pq->pq_flushg > 0 ||
+ (pq->pq_flushu > 0 && (pte & pmap_pg_g) == 0)) {
+ simple_unlock(&pq->pq_slock);
+ continue;
+ }
+
#ifdef I386_CPU
/*
* i386 CPUs can't invalidate a single VA, only
@@ -3484,23 +3498,26 @@
pq->pq_flushg = 0;
pq->pq_flushu = 0;
pmap_tlb_shootdown_q_drain(pq);
- } else if (pq->pq_flushu) {
- COUNT(flushu);
- tlbflush();
- pq->pq_flushu = 0;
- pmap_tlb_shootdown_q_drain(pq);
} else {
+ /*
+ * TLB flushes for PTEs with PG_G set may be in the queue
+ * after a flushu, they need to be dealt with.
+ */
+ if (pq->pq_flushu) {
+ COUNT(flushu);
+ tlbflush();
+ }
while ((pj = TAILQ_FIRST(&pq->pq_head)) != NULL) {
TAILQ_REMOVE(&pq->pq_head, pj, pj_list);
- if (pmap_is_curpmap(pj->pj_pmap) ||
- (pj->pj_pte & PG_G))
+ if ((!pq->pq_flushu && pmap_is_curpmap(pj->pj_pmap)) ||
+ (pj->pj_pte & pmap_pg_g))
pmap_update_pg(pj->pj_va);
pmap_tlb_shootdown_job_put(pq, pj);
}
- pq->pq_pte = 0;
+ pq->pq_flushu = pq->pq_pte = 0;
}
simple_unlock(&pq->pq_slock);
#if 0
Home |
Main Index |
Thread Index |
Old Index