summaryrefslogtreecommitdiff
path: root/usr/src/uts/i86pc/vm/hat_i86.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/i86pc/vm/hat_i86.c')
-rw-r--r--usr/src/uts/i86pc/vm/hat_i86.c44
1 files changed, 34 insertions, 10 deletions
diff --git a/usr/src/uts/i86pc/vm/hat_i86.c b/usr/src/uts/i86pc/vm/hat_i86.c
index 8da02a4c36..40b033d0e4 100644
--- a/usr/src/uts/i86pc/vm/hat_i86.c
+++ b/usr/src/uts/i86pc/vm/hat_i86.c
@@ -27,6 +27,7 @@
*/
/*
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
+ * Copyright 2012 Joyent, Inc. All rights reserved.
*/
/*
@@ -3350,15 +3351,13 @@ hati_page_unmap(page_t *pp, htable_t *ht, uint_t entry)
extern int vpm_enable;
/*
- * Unload all translations to a page. If the page is a subpage of a large
+ * Unload translations to a page. If the page is a subpage of a large
* page, the large page mappings are also removed.
- *
- * The forceflags are unused.
+ * If unloadflag is HAT_CURPROC_PGUNLOAD, then we only unload the translation
+ * for the current process, otherwise all translations are unloaded.
*/
-
-/*ARGSUSED*/
static int
-hati_pageunload(struct page *pp, uint_t pg_szcd, uint_t forceflag)
+hati_pageunload(struct page *pp, uint_t pg_szcd, uint_t unloadflag)
{
page_t *cur_pp = pp;
hment_t *hm;
@@ -3366,6 +3365,8 @@ hati_pageunload(struct page *pp, uint_t pg_szcd, uint_t forceflag)
htable_t *ht;
uint_t entry;
level_t level;
+ struct hat *curhat;
+ ulong_t cnt;
XPV_DISALLOW_MIGRATE();
@@ -3375,6 +3376,9 @@ hati_pageunload(struct page *pp, uint_t pg_szcd, uint_t forceflag)
++curthread->t_hatdepth;
ASSERT(curthread->t_hatdepth < 16);
+ if (unloadflag == HAT_CURPROC_PGUNLOAD)
+ curhat = curthread->t_procp->p_as->a_hat;
+
#if defined(__amd64)
/*
* clear the vpm ref.
@@ -3387,6 +3391,8 @@ hati_pageunload(struct page *pp, uint_t pg_szcd, uint_t forceflag)
* The loop with next_size handles pages with multiple pagesize mappings
*/
next_size:
+ if (unloadflag == HAT_CURPROC_PGUNLOAD)
+ cnt = hat_page_getshare(cur_pp);
for (;;) {
/*
@@ -3398,6 +3404,7 @@ next_size:
if (hm == NULL) {
x86_hm_exit(cur_pp);
+curproc_done:
/*
* If not part of a larger page, we're done.
*/
@@ -3424,8 +3431,21 @@ next_size:
* If this mapping size matches, remove it.
*/
level = ht->ht_level;
- if (level == pg_szcd)
- break;
+ if (level == pg_szcd) {
+ if (unloadflag != HAT_CURPROC_PGUNLOAD ||
+ ht->ht_hat == curhat)
+ break;
+ /*
+ * unloadflag == HAT_CURPROC_PGUNLOAD but it's
+ * not the hat for the current process. Leave
+ * entry in place. Also do a safety check to
+ * ensure we don't get in an infinite loop
+ */
+ if (cnt-- == 0) {
+ x86_hm_exit(cur_pp);
+ goto curproc_done;
+ }
+ }
}
/*
@@ -3435,14 +3455,18 @@ next_size:
hm = hati_page_unmap(cur_pp, ht, entry);
if (hm != NULL)
hment_free(hm);
+
+ /* Perform check above for being part of a larger page. */
+ if (unloadflag == HAT_CURPROC_PGUNLOAD)
+ goto curproc_done;
}
}
int
-hat_pageunload(struct page *pp, uint_t forceflag)
+hat_pageunload(struct page *pp, uint_t unloadflag)
{
ASSERT(PAGE_EXCL(pp));
- return (hati_pageunload(pp, 0, forceflag));
+ return (hati_pageunload(pp, 0, unloadflag));
}
/*