Print this page
OS-3088 need a lighterweight page invalidation mechanism for zone memcap
OS-881 To workaround OS-580 add support to only invalidate mappings from a single process
*** 26,35 ****
--- 26,36 ----
* All rights reserved.
*/
/*
* Copyright 2011 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2014, 2015 by Delphix. All rights reserved.
+ * Copyright 2014 Joyent, Inc. All rights reserved.
*/
/*
* VM - Hardware Address Translation management for i386 and amd64
*
*** 3321,3331 ****
return (PP_GETRM(pp, flag));
}
/*
! * common code used by hat_pageunload() and hment_steal()
*/
hment_t *
hati_page_unmap(page_t *pp, htable_t *ht, uint_t entry)
{
x86pte_t old_pte;
--- 3322,3332 ----
return (PP_GETRM(pp, flag));
}
/*
! * common code used by hat_page_inval() and hment_steal()
*/
hment_t *
hati_page_unmap(page_t *pp, htable_t *ht, uint_t entry)
{
x86pte_t old_pte;
*** 3377,3411 ****
return (hm);
}
extern int vpm_enable;
/*
! * Unload all 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.
*/
!
! /*ARGSUSED*/
! static int
! hati_pageunload(struct page *pp, uint_t pg_szcd, uint_t forceflag)
{
page_t *cur_pp = pp;
hment_t *hm;
hment_t *prev;
htable_t *ht;
uint_t entry;
level_t level;
XPV_DISALLOW_MIGRATE();
- /*
- * prevent recursion due to kmem_free()
- */
- ++curthread->t_hatdepth;
- ASSERT(curthread->t_hatdepth < 16);
-
#if defined(__amd64)
/*
* clear the vpm ref.
*/
if (vpm_enable) {
--- 3378,3405 ----
return (hm);
}
extern int vpm_enable;
/*
! * Unload translations to a page. If the page is a subpage of a large
* page, the large page mappings are also removed.
! * If curhat is not NULL, then we only unload the translation
! * for the given process, otherwise all translations are unloaded.
*/
! void
! hat_page_inval(struct page *pp, uint_t pg_szcd, struct hat *curhat)
{
page_t *cur_pp = pp;
hment_t *hm;
hment_t *prev;
htable_t *ht;
uint_t entry;
level_t level;
+ ulong_t cnt;
XPV_DISALLOW_MIGRATE();
#if defined(__amd64)
/*
* clear the vpm ref.
*/
if (vpm_enable) {
*** 3414,3423 ****
--- 3408,3419 ----
#endif
/*
* The loop with next_size handles pages with multiple pagesize mappings
*/
next_size:
+ if (curhat != NULL)
+ cnt = hat_page_getshare(cur_pp);
for (;;) {
/*
* Get a mapping list entry
*/
*** 3425,3442 ****
for (prev = NULL; ; prev = hm) {
hm = hment_walk(cur_pp, &ht, &entry, prev);
if (hm == NULL) {
x86_hm_exit(cur_pp);
/*
* If not part of a larger page, we're done.
*/
if (cur_pp->p_szc <= pg_szcd) {
- ASSERT(curthread->t_hatdepth > 0);
- --curthread->t_hatdepth;
XPV_ALLOW_MIGRATE();
! return (0);
}
/*
* Else check the next larger page size.
* hat_page_demote() may decrease p_szc
--- 3421,3437 ----
for (prev = NULL; ; prev = hm) {
hm = hment_walk(cur_pp, &ht, &entry, prev);
if (hm == NULL) {
x86_hm_exit(cur_pp);
+ curproc_done:
/*
* If not part of a larger page, we're done.
*/
if (cur_pp->p_szc <= pg_szcd) {
XPV_ALLOW_MIGRATE();
! return;
}
/*
* Else check the next larger page size.
* hat_page_demote() may decrease p_szc
*** 3451,3479 ****
/*
* If this mapping size matches, remove it.
*/
level = ht->ht_level;
! if (level == pg_szcd)
break;
}
/*
* Remove the mapping list entry for this page.
* Note this does the x86_hm_exit() for us.
*/
hm = hati_page_unmap(cur_pp, ht, entry);
if (hm != NULL)
hment_free(hm);
}
}
int
! hat_pageunload(struct page *pp, uint_t forceflag)
{
ASSERT(PAGE_EXCL(pp));
! return (hati_pageunload(pp, 0, forceflag));
}
/*
* Unload all large mappings to pp and reduce by 1 p_szc field of every large
* page level that included pp.
--- 3446,3516 ----
/*
* If this mapping size matches, remove it.
*/
level = ht->ht_level;
! if (level == pg_szcd) {
! if (curhat == NULL || ht->ht_hat == curhat)
break;
+ /*
+ * Unloading only the given process 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;
}
+ }
+ }
/*
* Remove the mapping list entry for this page.
* Note this does the x86_hm_exit() for us.
*/
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 (curhat != NULL)
+ goto curproc_done;
}
}
+ /*
+ * Unload translations to a page. If unloadflag is HAT_CURPROC_PGUNLOAD, then
+ * we only unload the translation for the current process, otherwise all
+ * translations are unloaded.
+ */
+ static int
+ hati_pageunload(struct page *pp, uint_t pg_szcd, uint_t unloadflag)
+ {
+ struct hat *curhat = NULL;
+
+ /*
+ * prevent recursion due to kmem_free()
+ */
+ ++curthread->t_hatdepth;
+ ASSERT(curthread->t_hatdepth < 16);
+
+ if (unloadflag == HAT_CURPROC_PGUNLOAD)
+ curhat = curthread->t_procp->p_as->a_hat;
+
+ hat_page_inval(pp, pg_szcd, curhat);
+
+ ASSERT(curthread->t_hatdepth > 0);
+ --curthread->t_hatdepth;
+ return (0);
+ }
+
int
! hat_pageunload(struct page *pp, uint_t unloadflag)
{
ASSERT(PAGE_EXCL(pp));
! return (hati_pageunload(pp, 0, unloadflag));
}
/*
* Unload all large mappings to pp and reduce by 1 p_szc field of every large
* page level that included pp.