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