Page MenuHomeFreeBSD

D50970.id157553.diff
No OneTemporary

D50970.id157553.diff

diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
--- a/sys/amd64/amd64/pmap.c
+++ b/sys/amd64/amd64/pmap.c
@@ -1302,7 +1302,7 @@
static bool pmap_demote_pde_locked(pmap_t pmap, pd_entry_t *pde,
vm_offset_t va, struct rwlock **lockp);
static bool pmap_demote_pdpe(pmap_t pmap, pdp_entry_t *pdpe,
- vm_offset_t va);
+ vm_offset_t va, vm_page_t *mp);
static int pmap_enter_2mpage(pmap_t pmap, vm_offset_t va, vm_page_t m,
vm_prot_t prot, struct rwlock **lockp);
static int pmap_enter_pde(pmap_t pmap, vm_offset_t va, pd_entry_t newpde,
@@ -1334,7 +1334,7 @@
static pd_entry_t *pmap_pti_pde(vm_offset_t va);
static void pmap_pti_wire_pte(void *pte);
static int pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva,
- struct spglist *free, struct rwlock **lockp);
+ bool remove_pt, struct spglist *free, struct rwlock **lockp);
static int pmap_remove_pte(pmap_t pmap, pt_entry_t *ptq, vm_offset_t sva,
pd_entry_t ptepde, struct spglist *free, struct rwlock **lockp);
static vm_page_t pmap_remove_pt_page(pmap_t pmap, vm_offset_t va);
@@ -6066,7 +6066,7 @@
SLIST_INIT(&free);
sva = trunc_2mpage(va);
- pmap_remove_pde(pmap, pde, sva, &free, lockp);
+ pmap_remove_pde(pmap, pde, sva, false, &free, lockp);
if ((oldpde & pmap_global_bit(pmap)) == 0)
pmap_invalidate_pde_page(pmap, sva, oldpde);
vm_page_free_pages_toq(&free, true);
@@ -6220,7 +6220,8 @@
* pmap_remove_kernel_pde: Remove a kernel superpage mapping.
*/
static void
-pmap_remove_kernel_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va)
+pmap_remove_kernel_pde(pmap_t pmap, pd_entry_t *pde, vm_offset_t va,
+ bool remove_pt)
{
pd_entry_t newpde;
vm_paddr_t mptepa;
@@ -6228,7 +6229,10 @@
KASSERT(pmap == kernel_pmap, ("pmap %p is not kernel_pmap", pmap));
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
- mpte = pmap_remove_pt_page(pmap, va);
+ if (remove_pt)
+ mpte = pmap_remove_pt_page(pmap, va);
+ else
+ mpte = vm_radix_lookup(&pmap->pm_root, pmap_pde_pindex(va));
if (mpte == NULL)
panic("pmap_remove_kernel_pde: Missing pt page.");
@@ -6260,7 +6264,7 @@
* pmap_remove_pde: do the things to unmap a superpage in a process
*/
static int
-pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva,
+pmap_remove_pde(pmap_t pmap, pd_entry_t *pdq, vm_offset_t sva, bool remove_pt,
struct spglist *free, struct rwlock **lockp)
{
struct md_page *pvh;
@@ -6301,7 +6305,7 @@
}
}
if (pmap == kernel_pmap) {
- pmap_remove_kernel_pde(pmap, pdq, sva);
+ pmap_remove_kernel_pde(pmap, pdq, sva, remove_pt);
} else {
mpte = pmap_remove_pt_page(pmap, sva);
if (mpte != NULL) {
@@ -6543,7 +6547,8 @@
*/
if ((ptpaddr & PG_G) == 0)
anyvalid = 1;
- pmap_remove_pde(pmap, pde, sva, &free, &lock);
+ pmap_remove_pde(pmap, pde, sva, false, &free,
+ &lock);
continue;
} else if (!pmap_demote_pde_locked(pmap, pde, sva,
&lock)) {
@@ -7619,13 +7624,36 @@
/*
* The reference to the PD page that was acquired by
* pmap_alloc_pde() ensures that it won't be freed.
- * However, if the PDE resulted from a promotion, then
+ * However, if the PDE resulted from a promotion, and
+ * the mapping is not from kernel_pmap, then
* a reserved PT page could be freed.
*/
- (void)pmap_remove_pde(pmap, pde, va, &free, lockp);
+ (void)pmap_remove_pde(pmap, pde, va,
+ pmap != kernel_pmap, &free, lockp);
if ((oldpde & PG_G) == 0)
pmap_invalidate_pde_page(pmap, va, oldpde);
} else {
+ if (va >= VM_MAXUSER_ADDRESS) {
+ /*
+ * Try to save the ptp in the trie
+ * before any changes to mappings are
+ * made. Abort on failure.
+ */
+ mt = PHYS_TO_VM_PAGE(*pde & PG_FRAME);
+ if (pmap_insert_pt_page(pmap, mt, false, false)) {
+ if (pdpg != NULL)
+ pdpg->ref_count--;
+ CTR1(KTR_PMAP,
+ "pmap_enter_pde: cannot ins kern ptp va %#lx",
+ va);
+ return (KERN_RESOURCE_SHORTAGE);
+ }
+ /*
+ * Both pmap_remove_pde() and
+ * pmap_remove_ptes() will set the
+ * kernel page table page zero filled.
+ */
+ }
pmap_delayed_invl_start();
if (pmap_remove_ptes(pmap, va, va + NBPDR, pde, &free,
lockp))
@@ -7639,14 +7667,6 @@
} else {
KASSERT(SLIST_EMPTY(&free),
("pmap_enter_pde: freed kernel page table page"));
-
- /*
- * Both pmap_remove_pde() and pmap_remove_ptes() will
- * leave the kernel page table page zero filled.
- */
- mt = PHYS_TO_VM_PAGE(*pde & PG_FRAME);
- if (pmap_insert_pt_page(pmap, mt, false, false))
- panic("pmap_enter_pde: trie insert failed");
}
}
@@ -9614,7 +9634,7 @@
* Tries to demote a 1GB page mapping.
*/
static bool
-pmap_demote_pdpe(pmap_t pmap, pdp_entry_t *pdpe, vm_offset_t va)
+pmap_demote_pdpe(pmap_t pmap, pdp_entry_t *pdpe, vm_offset_t va, vm_page_t *mp)
{
pdp_entry_t newpdpe, oldpdpe;
pd_entry_t *firstpde, newpde, *pde;
@@ -9631,12 +9651,20 @@
oldpdpe = *pdpe;
KASSERT((oldpdpe & (PG_PS | PG_V)) == (PG_PS | PG_V),
("pmap_demote_pdpe: oldpdpe is missing PG_PS and/or PG_V"));
- pdpg = pmap_alloc_pt_page(pmap, va >> PDPSHIFT,
- VM_ALLOC_WIRED | VM_ALLOC_INTERRUPT);
- if (pdpg == NULL) {
- CTR2(KTR_PMAP, "pmap_demote_pdpe: failure for va %#lx"
- " in pmap %p", va, pmap);
- return (false);
+ if (mp == NULL) {
+ pdpg = pmap_alloc_pt_page(pmap, va >> PDPSHIFT,
+ VM_ALLOC_WIRED);
+ if (pdpg == NULL) {
+ CTR2(KTR_PMAP,
+ "pmap_demote_pdpe: failure for va %#lx in pmap %p",
+ va, pmap);
+ return (false);
+ }
+ } else {
+ pdpg = *mp;
+ *mp = NULL;
+ pdpg->pindex = va >> PDPSHIFT;
+ pmap_pt_page_count_adj(pmap, 1);
}
pdpgpa = VM_PAGE_TO_PHYS(pdpg);
firstpde = (pd_entry_t *)PHYS_TO_DMAP(pdpgpa);
@@ -9846,7 +9874,7 @@
tmpva += NBPDP;
continue;
}
- if (!pmap_demote_pdpe(kernel_pmap, pdpe, tmpva))
+ if (!pmap_demote_pdpe(kernel_pmap, pdpe, tmpva, NULL))
return (ENOMEM);
}
pde = pmap_pdpe_to_pde(pdpe, tmpva);
@@ -10004,17 +10032,20 @@
}
/*
- * Demotes any mapping within the direct map region that covers more than the
- * specified range of physical addresses. This range's size must be a power
- * of two and its starting address must be a multiple of its size. Since the
- * demotion does not change any attributes of the mapping, a TLB invalidation
- * is not mandatory. The caller may, however, request a TLB invalidation.
+ * Demotes any mapping within the direct map region that covers more
+ * than the specified range of physical addresses. This range's size
+ * must be a power of two and its starting address must be a multiple
+ * of its size, which means that any pdp from the mapping is fully
+ * covered by the range if len > NBPDP. Since the demotion does not
+ * change any attributes of the mapping, a TLB invalidation is not
+ * mandatory. The caller may, however, request a TLB invalidation.
*/
void
pmap_demote_DMAP(vm_paddr_t base, vm_size_t len, bool invalidate)
{
pdp_entry_t *pdpe;
pd_entry_t *pde;
+ vm_page_t m;
vm_offset_t va;
bool changed;
@@ -10023,15 +10054,24 @@
KASSERT(powerof2(len), ("pmap_demote_DMAP: len is not a power of 2"));
KASSERT((base & (len - 1)) == 0,
("pmap_demote_DMAP: base is not a multiple of len"));
+ m = NULL;
if (len < NBPDP && base < dmaplimit) {
va = PHYS_TO_DMAP(base);
changed = false;
+
+ /*
+ * Assume that it is fine to sleep there.
+ * The only existing caller of pmap_demote_DMAP() is the
+ * x86_mr_split_dmap() function.
+ */
+ m = vm_page_alloc_noobj(VM_ALLOC_WIRED | VM_ALLOC_WAITOK);
+
PMAP_LOCK(kernel_pmap);
pdpe = pmap_pdpe(kernel_pmap, va);
if ((*pdpe & X86_PG_V) == 0)
panic("pmap_demote_DMAP: invalid PDPE");
if ((*pdpe & PG_PS) != 0) {
- if (!pmap_demote_pdpe(kernel_pmap, pdpe, va))
+ if (!pmap_demote_pdpe(kernel_pmap, pdpe, va, &m))
panic("pmap_demote_DMAP: PDPE failed");
changed = true;
}
@@ -10049,6 +10089,10 @@
pmap_invalidate_page(kernel_pmap, va);
PMAP_UNLOCK(kernel_pmap);
}
+ if (m != NULL) {
+ vm_page_unwire_noq(m);
+ vm_page_free(m);
+ }
}
/*
diff --git a/sys/dev/mem/memutil.c b/sys/dev/mem/memutil.c
--- a/sys/dev/mem/memutil.c
+++ b/sys/dev/mem/memutil.c
@@ -26,15 +26,14 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/memrange.h>
-#include <sys/rwlock.h>
-#include <sys/systm.h>
+#include <sys/sx.h>
-static struct rwlock mr_lock;
+static struct sx mr_lock;
/*
* Implementation-neutral, kernel-callable functions for manipulating
@@ -46,7 +45,7 @@
if (mem_range_softc.mr_op == NULL)
return;
- rw_init(&mr_lock, "memrange");
+ sx_init(&mr_lock, "memrange");
mem_range_softc.mr_op->init(&mem_range_softc);
}
@@ -56,7 +55,7 @@
if (mem_range_softc.mr_op == NULL)
return;
- rw_destroy(&mr_lock);
+ sx_destroy(&mr_lock);
}
int
@@ -67,12 +66,12 @@
if (mem_range_softc.mr_op == NULL)
return (EOPNOTSUPP);
nd = *arg;
- rw_rlock(&mr_lock);
+ sx_slock(&mr_lock);
if (nd == 0)
*arg = mem_range_softc.mr_ndesc;
else
bcopy(mem_range_softc.mr_desc, mrd, nd * sizeof(*mrd));
- rw_runlock(&mr_lock);
+ sx_sunlock(&mr_lock);
return (0);
}
@@ -83,8 +82,8 @@
if (mem_range_softc.mr_op == NULL)
return (EOPNOTSUPP);
- rw_wlock(&mr_lock);
+ sx_xlock(&mr_lock);
ret = mem_range_softc.mr_op->set(&mem_range_softc, mrd, arg);
- rw_wunlock(&mr_lock);
+ sx_xunlock(&mr_lock);
return (ret);
}

File Metadata

Mime Type
text/plain
Expires
Mon, Feb 9, 2:03 PM (13 h, 33 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28586422
Default Alt Text
D50970.id157553.diff (9 KB)

Event Timeline