aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndres Lagar-Cavilla <andres@lagarcavilla.org>2012-02-10 16:07:07 +0000
committerAndres Lagar-Cavilla <andres@lagarcavilla.org>2012-02-10 16:07:07 +0000
commit2da4c17b3b76d190da3dda35aa24910ff69984e5 (patch)
treeb101588084637ea1a07786224096b45613e6afa0
parentbb9e2139bca549fb8fd52c6fef4054b3ebf9ff3e (diff)
downloadxen-2da4c17b3b76d190da3dda35aa24910ff69984e5.tar.gz
xen-2da4c17b3b76d190da3dda35aa24910ff69984e5.tar.bz2
xen-2da4c17b3b76d190da3dda35aa24910ff69984e5.zip
x86/mm: When removing/adding a page from/to the physmap, keep in mind it could be shared
When removing the m2p mapping it is unconditionally set to invalid, which breaks sharing. When adding to the physmap, if the previous holder of that entry is a shared page, we unshare to default to normal case handling. And, we cannot add a shared page directly to the physmap. Proper interfaces must be employed, otherwise book-keeping goes awry. Signed-off-by: Andres Lagar-Cavilla <andres@lagarcavilla.org> Acked-by: Tim Deegan <tim@xen.org> Committed-by: Tim Deegan <tim@xen.org>
-rw-r--r--xen/arch/x86/mm/p2m.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index 645c7f90f6..233853b493 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -438,7 +438,7 @@ p2m_remove_page(struct p2m_domain *p2m, unsigned long gfn, unsigned long mfn,
for ( i = 0; i < (1UL << page_order); i++ )
{
mfn_return = p2m->get_entry(p2m, gfn + i, &t, &a, p2m_query, NULL);
- if ( !p2m_is_grant(t) )
+ if ( !p2m_is_grant(t) && !p2m_is_shared(t) )
set_gpfn_from_mfn(mfn+i, INVALID_M2P_ENTRY);
ASSERT( !p2m_is_valid(t) || mfn + i == mfn_x(mfn_return) );
}
@@ -500,6 +500,22 @@ guest_physmap_add_entry(struct domain *d, unsigned long gfn,
for ( i = 0; i < (1UL << page_order); i++ )
{
omfn = p2m->get_entry(p2m, gfn + i, &ot, &a, p2m_query, NULL);
+#ifdef __x86_64__
+ if ( p2m_is_shared(ot) )
+ {
+ /* Do an unshare to cleanly take care of all corner
+ * cases. */
+ int rc;
+ rc = mem_sharing_unshare_page(p2m->domain, gfn + i, 0);
+ if ( rc )
+ {
+ p2m_unlock(p2m);
+ return rc;
+ }
+ omfn = p2m->get_entry(p2m, gfn + i, &ot, &a, p2m_query, NULL);
+ ASSERT(!p2m_is_shared(ot));
+ }
+#endif /* __x86_64__ */
if ( p2m_is_grant(ot) )
{
/* Really shouldn't be unmapping grant maps this way */
@@ -528,6 +544,14 @@ guest_physmap_add_entry(struct domain *d, unsigned long gfn,
/* Then, look for m->p mappings for this range and deal with them */
for ( i = 0; i < (1UL << page_order); i++ )
{
+ if ( page_get_owner(mfn_to_page(_mfn(mfn + i))) == dom_cow )
+ {
+ /* This is no way to add a shared page to your physmap! */
+ gdprintk(XENLOG_ERR, "Adding shared mfn %lx directly to dom %hu "
+ "physmap not allowed.\n", mfn+i, d->domain_id);
+ p2m_unlock(p2m);
+ return -EINVAL;
+ }
if ( page_get_owner(mfn_to_page(_mfn(mfn + i))) != d )
continue;
ogfn = mfn_to_gfn(d, _mfn(mfn+i));