diff options
author | alc <alc@FreeBSD.org> | 2008-07-27 17:32:36 +0000 |
---|---|---|
committer | alc <alc@FreeBSD.org> | 2008-07-27 17:32:36 +0000 |
commit | 4455d56f31fa7e9832f76eb898382b8cf2d73aca (patch) | |
tree | 4a7f48afd1162cf545375899a65e415fbaede608 | |
parent | 3f1807709d7cfe3766d846df960fb657feef0ffb (diff) | |
download | FreeBSD-src-4455d56f31fa7e9832f76eb898382b8cf2d73aca.zip FreeBSD-src-4455d56f31fa7e9832f76eb898382b8cf2d73aca.tar.gz |
Enhance pmap_change_attr(). Use pmap_demote_pde() to demote a 2MB page
mapping to 4KB page mappings when the specified attribute change only
applies to a portion of the 2MB page. Previously, in such cases,
pmap_change_attr() gave up and returned an error.
Submitted by: Magesh Dhasayyan
-rw-r--r-- | sys/amd64/amd64/pmap.c | 31 |
1 files changed, 22 insertions, 9 deletions
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index 4f8c967..a246668 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -4373,27 +4373,40 @@ pmap_change_attr(va, size, mode) return (EINVAL); /* - * XXX: We have to support tearing 2MB pages down into 4k pages if - * needed here. + * Pages that aren't mapped aren't supported. Also break down 2MB pages + * into 4KB pages if required. */ - /* Pages that aren't mapped aren't supported. */ - for (tmpva = base; tmpva < (base + size); ) { + PMAP_LOCK(kernel_pmap); + for (tmpva = base; tmpva < base + size; ) { pde = pmap_pde(kernel_pmap, tmpva); - if (*pde == 0) + if (*pde == 0) { + PMAP_UNLOCK(kernel_pmap); return (EINVAL); + } if (*pde & PG_PS) { - /* Handle 2MB pages that are completely contained. */ - if (size >= NBPDR) { + /* + * If the current offset aligns with a 2MB page frame + * and there is at least 2MB left within the range, then + * we need not break down this page into 4KB pages. + */ + if ((tmpva & PDRMASK) == 0 && + tmpva + PDRMASK < base + size) { tmpva += NBPDR; continue; } - return (EINVAL); + if (!pmap_demote_pde(kernel_pmap, pde, tmpva)) { + PMAP_UNLOCK(kernel_pmap); + return (ENOMEM); + } } pte = vtopte(tmpva); - if (*pte == 0) + if (*pte == 0) { + PMAP_UNLOCK(kernel_pmap); return (EINVAL); + } tmpva += PAGE_SIZE; } + PMAP_UNLOCK(kernel_pmap); /* * Ok, all the pages exist, so run through them updating their |