aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiu, Jinsong <jinsong.liu@intel.com>2011-04-07 15:26:21 +0100
committerLiu, Jinsong <jinsong.liu@intel.com>2011-04-07 15:26:21 +0100
commitab302054f2f44e373bdacca73d74d0033957ab88 (patch)
tree6d3b2e9ec97910fcf7cf1edc8d10d415062da91a
parent7aa833f18ea19c95d7a0bdb3f163e9917573eaf5 (diff)
downloadxen-ab302054f2f44e373bdacca73d74d0033957ab88.tar.gz
xen-ab302054f2f44e373bdacca73d74d0033957ab88.tar.bz2
xen-ab302054f2f44e373bdacca73d74d0033957ab88.zip
X86: offline/broken page handler for pod cache
When offline a page, or, when a broken page occur, the page maybe populated, or, may at pod cache. This patch is to handle the offline/broken page at pod cache. It scan pod cache, if hit, remove and replace it, and then put the offline/broken page to page_offlined_list/page_broken_list Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com> xen-unstable changeset: 23178:fd8b81db422d xen-unstable date: Thu Apr 07 12:12:38 2011 +0100
-rw-r--r--xen/arch/x86/mm/p2m.c72
-rw-r--r--xen/common/page_alloc.c18
-rw-r--r--xen/include/asm-x86/p2m.h8
3 files changed, 98 insertions, 0 deletions
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index a8c0d6cb8a..ce24673ecf 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -681,6 +681,78 @@ p2m_pod_empty_cache(struct domain *d)
spin_unlock(&d->page_alloc_lock);
}
+int
+p2m_pod_offline_or_broken_hit(struct page_info *p)
+{
+ struct domain *d;
+ struct p2m_domain *p2m;
+ struct page_info *q, *tmp;
+ unsigned long mfn, bmfn;
+
+ if ( !(d = page_get_owner(p)) || !(p2m = p2m_get_hostp2m(d)) )
+ return 0;
+
+ spin_lock(&d->page_alloc_lock);
+ bmfn = mfn_x(page_to_mfn(p));
+ page_list_for_each_safe(q, tmp, &p2m->pod.super)
+ {
+ mfn = mfn_x(page_to_mfn(q));
+ if ( (bmfn >= mfn) && ((bmfn - mfn) < SUPERPAGE_PAGES) )
+ {
+ unsigned long i;
+ page_list_del(q, &p2m->pod.super);
+ for ( i = 0; i < SUPERPAGE_PAGES; i++)
+ {
+ q = mfn_to_page(_mfn(mfn + i));
+ page_list_add_tail(q, &p2m->pod.single);
+ }
+ page_list_del(p, &p2m->pod.single);
+ p2m->pod.count--;
+ goto pod_hit;
+ }
+ }
+
+ page_list_for_each_safe(q, tmp, &p2m->pod.single)
+ {
+ mfn = mfn_x(page_to_mfn(q));
+ if ( mfn == bmfn )
+ {
+ page_list_del(p, &p2m->pod.single);
+ p2m->pod.count--;
+ goto pod_hit;
+ }
+ }
+
+ spin_unlock(&d->page_alloc_lock);
+ return 0;
+
+pod_hit:
+ page_list_add_tail(p, &d->arch.relmem_list);
+ spin_unlock(&d->page_alloc_lock);
+ return 1;
+}
+
+void
+p2m_pod_offline_or_broken_replace(struct page_info *p)
+{
+ struct domain *d;
+ struct p2m_domain *p2m;
+
+ if ( !(d = page_get_owner(p)) || !(p2m = p2m_get_hostp2m(d)) )
+ return;
+
+ free_domheap_page(p);
+
+ p = alloc_domheap_page(d, 0);
+ if ( unlikely(!p) )
+ return;
+
+ p2m_lock(p2m);
+ p2m_pod_cache_add(p2m, p, 0);
+ p2m_unlock(p2m);
+ return;
+}
+
/* This function is needed for two reasons:
* + To properly handle clearing of PoD entries
* + To "steal back" memory being freed for the PoD cache, rather than
diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index 46b4b5c557..0d53cef79f 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -41,6 +41,7 @@
#include <asm/page.h>
#include <asm/numa.h>
#include <asm/flushtlb.h>
+#include <asm/p2m.h>
/*
* Comma-separated list of hexadecimal page numbers containing bad bytes.
@@ -714,10 +715,15 @@ int offline_page(unsigned long mfn, int broken, uint32_t *status)
}
else if ( (owner = page_get_owner_and_reference(pg)) )
{
+ if ( p2m_pod_offline_or_broken_hit(pg) )
+ goto pod_replace;
+ else
+ {
*status = PG_OFFLINE_OWNED | PG_OFFLINE_PENDING |
(owner->domain_id << PG_OFFLINE_OWNER_SHIFT);
/* Release the reference since it will not be allocated anymore */
put_page(pg);
+ }
}
else if ( old_info & PGC_xen_heap )
{
@@ -744,6 +750,18 @@ int offline_page(unsigned long mfn, int broken, uint32_t *status)
spin_unlock(&heap_lock);
return ret;
+
+pod_replace:
+ put_page(pg);
+ spin_unlock(&heap_lock);
+
+ p2m_pod_offline_or_broken_replace(pg);
+ *status = PG_OFFLINE_OFFLINED;
+
+ if ( broken )
+ *status |= PG_OFFLINE_BROKEN;
+
+ return ret;
}
/*
diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h
index 2e6941e13e..92e0703667 100644
--- a/xen/include/asm-x86/p2m.h
+++ b/xen/include/asm-x86/p2m.h
@@ -457,6 +457,14 @@ p2m_pod_demand_populate(struct p2m_domain *p2m, unsigned long gfn,
unsigned int order,
p2m_query_t q);
+/* Scan pod cache when offline/broken page triggered */
+int
+p2m_pod_offline_or_broken_hit(struct page_info *p);
+
+/* Replace pod cache when offline/broken page triggered */
+void
+p2m_pod_offline_or_broken_replace(struct page_info *p);
+
/* Add a page to a domain's p2m table */
int guest_physmap_add_entry(struct p2m_domain *p2m, unsigned long gfn,
unsigned long mfn, unsigned int page_order,