kernel - MPSAFE work - Basic tokenization for vkernel i386 pmap.c
authorMatthew Dillon <dillon@apollo.backplane.com>
Tue, 6 Jul 2010 04:31:09 +0000 (21:31 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 6 Jul 2010 04:31:09 +0000 (21:31 -0700)
* Tokenize the vkernel i386 pmap.c file
* Add minor documentation to x86_64 pmap.c

sys/platform/pc64/x86_64/pmap.c
sys/platform/vkernel/platform/pmap.c

index b43291d..fef9c60 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * (MPSAFE)
+ *
  * Copyright (c) 1991 Regents of the University of California.
  * Copyright (c) 1994 John S. Dyson
  * Copyright (c) 1994 David Greenman
index 9374dd3..9cc3aed 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * (MPSAFE)
+ *
  * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
  * Copyright (c) 1991 Regents of the University of California.
  * All rights reserved.
@@ -234,10 +236,13 @@ pmap_pinit(struct pmap *pmap)
 
 /*
  * Clean up a pmap structure so it can be physically freed
+ *
+ * No requirements.
  */
 void
 pmap_puninit(pmap_t pmap)
 {
+       lwkt_gettoken(&vm_token);
        if (pmap->pm_pdir) {
                kmem_free(&kernel_map, (vm_offset_t)pmap->pm_pdir, PAGE_SIZE);
                pmap->pm_pdir = NULL;
@@ -246,6 +251,7 @@ pmap_puninit(pmap_t pmap)
                vm_object_deallocate(pmap->pm_pteobj);
                pmap->pm_pteobj = NULL;
        }
+       lwkt_reltoken(&vm_token);
 }
 
 
@@ -256,12 +262,16 @@ pmap_puninit(pmap_t pmap)
  * then copies the template.
  *
  * In a virtual kernel there are no kernel global address entries.
+ *
+ * No requirements.
  */
 void
 pmap_pinit2(struct pmap *pmap)
 {
        crit_enter();
+       lwkt_gettoken(&vm_token);
        TAILQ_INSERT_TAIL(&pmap_list, pmap, pm_pmnode);
+       lwkt_reltoken(&vm_token);
        crit_exit();
 }
 
@@ -269,6 +279,8 @@ pmap_pinit2(struct pmap *pmap)
  * Release all resources held by the given physical map.
  *
  * Should only be called if the map contains no valid mappings.
+ *
+ * No requirements.
  */
 static int pmap_release_callback(struct vm_page *p, void *data);
 
@@ -309,6 +321,7 @@ pmap_release(struct pmap *pmap)
        info.pmap = pmap;
        info.object = object;
        crit_enter();
+       lwkt_gettoken(&vm_token);
        TAILQ_REMOVE(&pmap_list, pmap, pm_pmnode);
        crit_exit();
 
@@ -332,6 +345,7 @@ pmap_release(struct pmap *pmap)
         */
        pmap->pm_pdirpte = 0;
        pmap->pm_cpucachemask = 0;
+       lwkt_reltoken(&vm_token);
 }
 
 /*
@@ -361,30 +375,35 @@ pmap_release_callback(struct vm_page *p, void *data)
 /*
  * Retire the given physical map from service.  Should only be called if
  * the map contains no valid mappings.
+ *
+ * No requirements.
  */
 void
 pmap_destroy(pmap_t pmap)
 {
-       int count;
-
        if (pmap == NULL)
                return;
 
-       count = --pmap->pm_count;
-       if (count == 0) {
+       lwkt_gettoken(&vm_token);
+       if (--pmap->pm_count == 0) {
                pmap_release(pmap);
                panic("destroying a pmap is not yet implemented");
        }
+       lwkt_reltoken(&vm_token);
 }
 
 /*
  * Add a reference to the specified pmap.
+ *
+ * No requirements.
  */
 void
 pmap_reference(pmap_t pmap)
 {
-       if (pmap != NULL) {
-               pmap->pm_count++;
+       if (pmap) {
+               lwkt_gettoken(&vm_token);
+               ++pmap->pm_count;
+               lwkt_reltoken(&vm_token);
        }
 }
 
@@ -869,15 +888,19 @@ pmap_dispose_proc(struct proc *p)
 /*
  * We pre-allocate all page table pages for kernel virtual memory so
  * this routine will only be called if KVM has been exhausted.
+ *
+ * No requirements.
  */
 void
 pmap_growkernel(vm_offset_t addr)
 {
        addr = (addr + PAGE_SIZE * NPTEPG) & ~(PAGE_SIZE * NPTEPG - 1);
 
+       lwkt_gettoken(&vm_token);
        if (addr > virtual_end - SEG_SIZE)
                panic("KVM exhausted");
        kernel_vm_end = addr;
+       lwkt_reltoken(&vm_token);
 }
 
 /*
@@ -1259,6 +1282,8 @@ get_pv_entry(void)
 /*
  * This routine is very drastic, but can save the system
  * in a pinch.
+ *
+ * No requirements.
  */
 void
 pmap_collect(void)
@@ -1269,6 +1294,7 @@ pmap_collect(void)
 
        if (pmap_pagedaemon_waken == 0)
                return;
+       lwkt_gettoken(&vm_token);
        pmap_pagedaemon_waken = 0;
 
        if (warningdone < 5) {
@@ -1283,6 +1309,7 @@ pmap_collect(void)
                        continue;
                pmap_remove_all(m);
        }
+       lwkt_reltoken(&vm_token);
 }
        
 /*
@@ -1426,15 +1453,15 @@ pmap_remove_page(struct pmap *pmap, vm_offset_t va)
 }
 
 /*
- * pmap_remove:
+ * Remove the given range of addresses from the specified map.
  *
- *     Remove the given range of addresses from the specified map.
+ * It is assumed that the start and end are properly rounded to the
+ * page size.
  *
- *     It is assumed that the start and end are properly
- *     rounded to the page size.
+ * This function may not be called from an interrupt if the pmap is
+ * not kernel_pmap.
  *
- *     This function may not be called from an interrupt if the pmap is
- *     not kernel_pmap.
+ * No requirements.
  */
 void
 pmap_remove(struct pmap *pmap, vm_offset_t sva, vm_offset_t eva)
@@ -1447,9 +1474,12 @@ pmap_remove(struct pmap *pmap, vm_offset_t sva, vm_offset_t eva)
        if (pmap == NULL)
                return;
 
+       lwkt_gettoken(&vm_token);
        KKASSERT(pmap->pm_stats.resident_count >= 0);
-       if (pmap->pm_stats.resident_count == 0)
+       if (pmap->pm_stats.resident_count == 0) {
+               lwkt_reltoken(&vm_token);
                return;
+       }
 
        /*
         * special handling of removing one page.  a very
@@ -1459,6 +1489,7 @@ pmap_remove(struct pmap *pmap, vm_offset_t sva, vm_offset_t eva)
        if (((sva + PAGE_SIZE) == eva) && 
                ((pmap->pm_pdir[(sva >> PDRSHIFT)] & VPTE_PS) == 0)) {
                pmap_remove_page(pmap, sva);
+               lwkt_reltoken(&vm_token);
                return;
        }
 
@@ -1520,15 +1551,16 @@ pmap_remove(struct pmap *pmap, vm_offset_t sva, vm_offset_t eva)
                                break;
                }
        }
+       lwkt_reltoken(&vm_token);
 }
 
 /*
- * pmap_remove_all:
- *
  * Removes this physical page from all physical maps in which it resides.
  * Reflects back modify bits to the pager.
  *
  * This routine may not be called from an interrupt.
+ *
+ * No requirements.
  */
 static void
 pmap_remove_all(vm_page_t m)
@@ -1547,6 +1579,7 @@ pmap_remove_all(vm_page_t m)
 #endif
 
        crit_enter();
+       lwkt_gettoken(&vm_token);
        while ((pv = TAILQ_FIRST(&m->md.pv_list)) != NULL) {
                KKASSERT(pv->pv_pmap->pm_stats.resident_count > 0);
                --pv->pv_pmap->pm_stats.resident_count;
@@ -1586,17 +1619,18 @@ pmap_remove_all(vm_page_t m)
                free_pv_entry(pv);
        }
        KKASSERT((m->flags & (PG_MAPPED | PG_WRITEABLE)) == 0);
+       lwkt_reltoken(&vm_token);
        crit_exit();
 }
 
 /*
- * pmap_protect:
+ * Set the physical protection on the specified range of this map
+ * as requested.
  *
- *     Set the physical protection on the specified range of this map
- *     as requested.
+ * This function may not be called from an interrupt if the map is
+ * not the kernel_pmap.
  *
- *     This function may not be called from an interrupt if the map is
- *     not the kernel_pmap.
+ * No requirements.
  */
 void
 pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
@@ -1618,6 +1652,7 @@ pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
        if (prot & VM_PROT_WRITE)
                return;
 
+       lwkt_gettoken(&vm_token);
        ptbase = get_ptbase(pmap, sva);
 
        sindex = (sva >> PAGE_SHIFT);
@@ -1688,6 +1723,7 @@ pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
                        }
                }
        }
+       lwkt_reltoken(&vm_token);
 }
 
 /*
@@ -1702,6 +1738,8 @@ pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
  *
  * NOTE: When entering a page at a KVA address, the pmap must be the
  * kernel_pmap.
+ *
+ * No requirements.
  */
 void
 pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
@@ -1718,6 +1756,8 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
 
        va &= VPTE_FRAME;
 
+       lwkt_gettoken(&vm_token);
+
        /*
         * Get the page table page.   The kernel_pmap's page table pages
         * are preallocated and have no associated vm_page_t.
@@ -1854,6 +1894,7 @@ validate:
                        vm_page_flag_set(m, PG_WRITEABLE);
        }
        KKASSERT((newpte & VPTE_MANAGED) == 0 || m->flags & PG_MAPPED);
+       lwkt_reltoken(&vm_token);
 }
 
 /*
@@ -1882,6 +1923,8 @@ pmap_enter_quick(pmap_t pmap, vm_offset_t va, vm_page_t m)
         */
        ptepindex = va >> PDRSHIFT;
 
+       lwkt_gettoken(&vm_token);
+
        do {
                /*
                 * Get the page directory entry
@@ -1917,6 +1960,7 @@ pmap_enter_quick(pmap_t pmap, vm_offset_t va, vm_page_t m)
        pte = pmap_pte(pmap, va);
        if (*pte) {
                pmap_unwire_pte_hold(pmap, mpte);
+               lwkt_reltoken(&vm_token);
                return;
        }
 
@@ -1946,11 +1990,15 @@ pmap_enter_quick(pmap_t pmap, vm_offset_t va, vm_page_t m)
                *pte = (vpte_t)pa | VPTE_V | VPTE_U | VPTE_MANAGED;
        /*pmap_inval_add(&info, pmap, va); shouldn't be needed 0->valid */
        /*pmap_inval_flush(&info); don't need for vkernel */
+       lwkt_reltoken(&vm_token);
 }
 
 /*
  * Extract the physical address for the translation at the specified
  * virtual address in the pmap.
+ *
+ * The caller must hold vm_token if non-blocking operation is desired.
+ * No requirements.
  */
 vm_paddr_t
 pmap_extract(pmap_t pmap, vm_offset_t va)
@@ -1958,6 +2006,7 @@ pmap_extract(pmap_t pmap, vm_offset_t va)
        vm_paddr_t rtval;
        vpte_t pte;
 
+       lwkt_gettoken(&vm_token);
        if (pmap && (pte = pmap->pm_pdir[va >> SEG_SHIFT]) != 0) {
                if (pte & VPTE_PS) {
                        rtval = pte & ~((vpte_t)(1 << SEG_SHIFT) - 1);
@@ -1966,9 +2015,11 @@ pmap_extract(pmap_t pmap, vm_offset_t va)
                        pte = *get_ptbase(pmap, va);
                        rtval = (pte & VPTE_FRAME) | (va & PAGE_MASK);
                }
-               return(rtval);
+       } else {
+               rtval = 0;
        }
-       return(0);
+       lwkt_reltoken(&vm_token);
+       return(rtval);
 }
 
 #define MAX_INIT_PT (96)
@@ -1977,6 +2028,8 @@ pmap_extract(pmap_t pmap, vm_offset_t va)
  * This routine preloads the ptes for a given object into the specified pmap.
  * This eliminates the blast of soft faults on process startup and
  * immediately after an mmap.
+ *
+ * No requirements.
  */
 static int pmap_object_init_pt_callback(vm_page_t p, void *data);
 
@@ -2035,11 +2088,16 @@ pmap_object_init_pt(pmap_t pmap, vm_offset_t addr, vm_prot_t prot,
        info.pmap = pmap;
 
        crit_enter();
+       lwkt_gettoken(&vm_token);
        vm_page_rb_tree_RB_SCAN(&object->rb_memq, rb_vm_page_scancmp,
                                pmap_object_init_pt_callback, &info);
+       lwkt_reltoken(&vm_token);
        crit_exit();
 }
 
+/*
+ * The caller must hold vm_token.
+ */
 static
 int
 pmap_object_init_pt_callback(vm_page_t p, void *data)
@@ -2073,28 +2131,31 @@ pmap_object_init_pt_callback(vm_page_t p, void *data)
  *
  * Returns FALSE if it would be non-trivial or if a
  * pte is already loaded into the slot.
+ *
+ * No requirements.
  */
 int
 pmap_prefault_ok(pmap_t pmap, vm_offset_t addr)
 {
        vpte_t *pte;
+       int ret;
 
-       if ((*pmap_pde(pmap, addr)) == 0)
-               return(0);
-
-       pte = get_ptbase(pmap, addr);
-       if (*pte)
-               return(0);
-
-       return(1);
+       lwkt_gettoken(&vm_token);
+       if ((*pmap_pde(pmap, addr)) == 0) {
+               ret = 0;
+       } else {
+               pte = get_ptbase(pmap, addr);
+               ret = (*pte) ? 0 : 1;
+       }
+       lwkt_reltoken(&vm_token);
+       return (ret);
 }
 
 /*
- *     Routine:        pmap_change_wiring
- *     Function:       Change the wiring attribute for a map/virtual-address
- *                     pair.
- *     In/out conditions:
- *                     The mapping must already exist in the pmap.
+ * Change the wiring attribute for a map/virtual-address pair.
+ * The mapping must already exist in the pmap.
+ *
+ * No other requirements.
  */
 void
 pmap_change_wiring(pmap_t pmap, vm_offset_t va, boolean_t wired)
@@ -2104,6 +2165,7 @@ pmap_change_wiring(pmap_t pmap, vm_offset_t va, boolean_t wired)
        if (pmap == NULL)
                return;
 
+       lwkt_gettoken(&vm_token);
        pte = get_ptbase(pmap, va);
 
        if (wired && (*pte & VPTE_WIRED) == 0)
@@ -2123,6 +2185,7 @@ pmap_change_wiring(pmap_t pmap, vm_offset_t va, boolean_t wired)
                atomic_set_long(pte, VPTE_WIRED);
        else
                atomic_clear_long(pte, VPTE_WIRED);
+       lwkt_reltoken(&vm_token);
 }
 
 /*
@@ -2411,6 +2474,8 @@ pmap_copy_page_frag(vm_paddr_t src, vm_paddr_t dst, size_t bytes)
  * be changed upwards or downwards in the future; it
  * is only necessary that true be returned for a small
  * subset of pmaps for proper page aging.
+ *
+ * No requirements.
  */
 boolean_t
 pmap_page_exists_quick(pmap_t pmap, vm_page_t m)
@@ -2422,9 +2487,11 @@ pmap_page_exists_quick(pmap_t pmap, vm_page_t m)
                return FALSE;
 
        crit_enter();
+       lwkt_gettoken(&vm_token);
 
        TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) {
                if (pv->pv_pmap == pmap) {
+                       lwkt_reltoken(&vm_token);
                        crit_exit();
                        return TRUE;
                }
@@ -2432,6 +2499,7 @@ pmap_page_exists_quick(pmap_t pmap, vm_page_t m)
                if (loops >= 16)
                        break;
        }
+       lwkt_reltoken(&vm_token);
        crit_exit();
        return (FALSE);
 }
@@ -2443,6 +2511,8 @@ pmap_page_exists_quick(pmap_t pmap, vm_page_t m)
  * can have the more generic (and slightly slower)
  * mode enabled.  This is much faster than pmap_remove
  * in the case of running down an entire address space.
+ *
+ * No requirements.
  */
 void
 pmap_remove_pages(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
@@ -2453,6 +2523,7 @@ pmap_remove_pages(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
        int32_t save_generation;
 
        crit_enter();
+       lwkt_gettoken(&vm_token);
        for (pv = TAILQ_FIRST(&pmap->pm_pvlist); pv; pv = npv) {
                if (pv->pv_va >= eva || pv->pv_va < sva) {
                        npv = TAILQ_NEXT(pv, pv_plist);
@@ -2509,11 +2580,14 @@ pmap_remove_pages(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
                        npv = TAILQ_FIRST(&pmap->pm_pvlist);
                }
        }
+       lwkt_reltoken(&vm_token);
        crit_exit();
 }
 
 /*
  * pmap_testbit tests bits in active mappings of a VM page.
+ *
+ * The caller must hold vm_token
  */
 static boolean_t
 pmap_testbit(vm_page_t m, int bit)
@@ -2561,6 +2635,8 @@ pmap_testbit(vm_page_t m, int bit)
  * handling, in particular (on virtual kernels) the VPTE_M (modify) bit.
  *
  * This routine is only called with certain VPTE_* bit combinations.
+ *
+ * The caller must hold vm_token
  */
 static __inline void
 pmap_clearbit(vm_page_t m, int bit)
@@ -2648,20 +2724,22 @@ pmap_clearbit(vm_page_t m, int bit)
 }
 
 /*
- *      pmap_page_protect:
+ * Lower the permission for all mappings to a given page.
  *
- *      Lower the permission for all mappings to a given page.
+ * No requirements.
  */
 void
 pmap_page_protect(vm_page_t m, vm_prot_t prot)
 {
        if ((prot & VM_PROT_WRITE) == 0) {
+               lwkt_gettoken(&vm_token);
                if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) {
                        pmap_clearbit(m, VPTE_W);
                        vm_page_flag_clear(m, PG_WRITEABLE);
                } else {
                        pmap_remove_all(m);
                }
+               lwkt_reltoken(&vm_token);
        }
 }
 
@@ -2672,16 +2750,16 @@ pmap_phys_address(vm_pindex_t ppn)
 }
 
 /*
- *     pmap_ts_referenced:
+ * Return a count of reference bits for a page, clearing those bits.
+ * It is not necessary for every reference bit to be cleared, but it
+ * is necessary that 0 only be returned when there are truly no
+ * reference bits set.
  *
- *     Return a count of reference bits for a page, clearing those bits.
- *     It is not necessary for every reference bit to be cleared, but it
- *     is necessary that 0 only be returned when there are truly no
- *     reference bits set.
+ * XXX: The exact number of bits to check and clear is a matter that
+ * should be tested and standardized at some point in the future for
+ * optimal aging of shared pages.
  *
- *     XXX: The exact number of bits to check and clear is a matter that
- *     should be tested and standardized at some point in the future for
- *     optimal aging of shared pages.
+ * No requirements.
  */
 int
 pmap_ts_referenced(vm_page_t m)
@@ -2694,6 +2772,7 @@ pmap_ts_referenced(vm_page_t m)
                return (rtval);
 
        crit_enter();
+       lwkt_gettoken(&vm_token);
 
        if ((pv = TAILQ_FIRST(&m->md.pv_list)) != NULL) {
 
@@ -2724,41 +2803,53 @@ pmap_ts_referenced(vm_page_t m)
                        }
                } while ((pv = pvn) != NULL && pv != pvf);
        }
+       lwkt_reltoken(&vm_token);
        crit_exit();
 
        return (rtval);
 }
 
 /*
- *     pmap_is_modified:
+ * Return whether or not the specified physical page was modified
+ * in any physical maps.
  *
- *     Return whether or not the specified physical page was modified
- *     in any physical maps.
+ * No requirements.
  */
 boolean_t
 pmap_is_modified(vm_page_t m)
 {
-       return pmap_testbit(m, VPTE_M);
+       boolean_t res;
+
+       lwkt_gettoken(&vm_token);
+       res = pmap_testbit(m, VPTE_M);
+       lwkt_reltoken(&vm_token);
+       return (res);
 }
 
 /*
- *     Clear the modify bits on the specified physical page.
+ * Clear the modify bits on the specified physical page.
+ *
+ * No requirements.
  */
 void
 pmap_clear_modify(vm_page_t m)
 {
+       lwkt_gettoken(&vm_token);
        pmap_clearbit(m, VPTE_M);
+       lwkt_reltoken(&vm_token);
 }
 
 /*
- *     pmap_clear_reference:
+ * Clear the reference bit on the specified physical page.
  *
- *     Clear the reference bit on the specified physical page.
+ * No requirements.
  */
 void
 pmap_clear_reference(vm_page_t m)
 {
+       lwkt_gettoken(&vm_token);
        pmap_clearbit(m, VPTE_A);
+       lwkt_reltoken(&vm_token);
 }
 
 /*
@@ -2835,7 +2926,9 @@ pmap_unmapdev(vm_offset_t va, vm_size_t size)
 #endif
 
 /*
- * perform the pmap work for mincore
+ * Perform the pmap work for mincore
+ *
+ * No requirements.
  */
 int
 pmap_mincore(pmap_t pmap, vm_offset_t addr)
@@ -2843,9 +2936,12 @@ pmap_mincore(pmap_t pmap, vm_offset_t addr)
        vpte_t *ptep, pte;
        vm_page_t m;
        int val = 0;
+
+       lwkt_gettoken(&vm_token);
        
        ptep = pmap_pte(pmap, addr);
        if (ptep == 0) {
+               lwkt_reltoken(&vm_token);
                return 0;
        }
 
@@ -2854,7 +2950,7 @@ pmap_mincore(pmap_t pmap, vm_offset_t addr)
 
                val = MINCORE_INCORE;
                if ((pte & VPTE_MANAGED) == 0)
-                       return val;
+                       goto done;
 
                pa = pte & VPTE_FRAME;
 
@@ -2884,6 +2980,8 @@ pmap_mincore(pmap_t pmap, vm_offset_t addr)
                        vm_page_flag_set(m, PG_REFERENCED);
                }
        } 
+done:
+       lwkt_reltoken(&vm_token);
        return val;
 }