aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorIan Campbell <ian.campbell@citrix.com>2010-10-21 06:00:46 -0400
committerJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>2010-10-22 15:57:36 -0400
commit375b2a9ada6d105483aab22f1af1d727bc3c418d (patch)
tree121f008f81d8424bdae575b8c2cad06c0dfd1a1f /arch
parentcb52e6d9ed9bb9cf74f8396a603ecf12b64c1ec1 (diff)
xen: correctly rebuild mfn list list after migration.
Otherwise the second migration attempt fails because the mfn_list_list still refers to all the old mfns. We need to update the entires in both p2m_top_mfn and the mid_mfn pages which p2m_top_mfn refers to. In order to do this we need to keep track of the virtual addresses mapping the p2m_mid_mfn pages since we cannot rely on mfn_to_virt(p2m_top_mfn[idx]) since p2m_top_mfn[idx] will still contain the old MFN after a migration, which may now belong to another domain and hence have a different mapping in the m2p. Therefore add and maintain a third top level page, p2m_top_mfn_p[], which tracks the virtual addresses of the mfns contained in p2m_top_mfn[]. We also need to update the content of the p2m_mid_missing_mfn page on resume to refer to the page's new mfn. p2m_missing does not need updating since the migration process takes care of the leaf p2m pages for us. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/xen/mmu.c50
1 files changed, 37 insertions, 13 deletions
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 67b41017f7b8..e41683cf290a 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -187,6 +187,8 @@ DEFINE_PER_CPU(unsigned long, xen_current_cr3); /* actual vcpu cr3 */
187 * / \ / \ / / 187 * / \ / \ / /
188 * p2m p2m p2m p2m p2m p2m p2m ... 188 * p2m p2m p2m p2m p2m p2m p2m ...
189 * 189 *
190 * The p2m_mid_mfn pages are mapped by p2m_top_mfn_p.
191 *
190 * The p2m_top and p2m_top_mfn levels are limited to 1 page, so the 192 * The p2m_top and p2m_top_mfn levels are limited to 1 page, so the
191 * maximum representable pseudo-physical address space is: 193 * maximum representable pseudo-physical address space is:
192 * P2M_TOP_PER_PAGE * P2M_MID_PER_PAGE * P2M_PER_PAGE pages 194 * P2M_TOP_PER_PAGE * P2M_MID_PER_PAGE * P2M_PER_PAGE pages
@@ -211,6 +213,7 @@ static RESERVE_BRK_ARRAY(unsigned long, p2m_mid_missing_mfn, P2M_MID_PER_PAGE);
211 213
212static RESERVE_BRK_ARRAY(unsigned long **, p2m_top, P2M_TOP_PER_PAGE); 214static RESERVE_BRK_ARRAY(unsigned long **, p2m_top, P2M_TOP_PER_PAGE);
213static RESERVE_BRK_ARRAY(unsigned long, p2m_top_mfn, P2M_TOP_PER_PAGE); 215static RESERVE_BRK_ARRAY(unsigned long, p2m_top_mfn, P2M_TOP_PER_PAGE);
216static RESERVE_BRK_ARRAY(unsigned long *, p2m_top_mfn_p, P2M_TOP_PER_PAGE);
214 217
215RESERVE_BRK(p2m_mid, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE))); 218RESERVE_BRK(p2m_mid, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE)));
216RESERVE_BRK(p2m_mid_mfn, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE))); 219RESERVE_BRK(p2m_mid_mfn, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE)));
@@ -247,6 +250,14 @@ static void p2m_top_mfn_init(unsigned long *top)
247 top[i] = virt_to_mfn(p2m_mid_missing_mfn); 250 top[i] = virt_to_mfn(p2m_mid_missing_mfn);
248} 251}
249 252
253static void p2m_top_mfn_p_init(unsigned long **top)
254{
255 unsigned i;
256
257 for (i = 0; i < P2M_TOP_PER_PAGE; i++)
258 top[i] = p2m_mid_missing_mfn;
259}
260
250static void p2m_mid_init(unsigned long **mid) 261static void p2m_mid_init(unsigned long **mid)
251{ 262{
252 unsigned i; 263 unsigned i;
@@ -283,33 +294,43 @@ static void p2m_init(unsigned long *p2m)
283 */ 294 */
284void xen_build_mfn_list_list(void) 295void xen_build_mfn_list_list(void)
285{ 296{
286 unsigned pfn; 297 unsigned long pfn;
287 298
288 /* Pre-initialize p2m_top_mfn to be completely missing */ 299 /* Pre-initialize p2m_top_mfn to be completely missing */
289 if (p2m_top_mfn == NULL) { 300 if (p2m_top_mfn == NULL) {
290 p2m_mid_missing_mfn = extend_brk(PAGE_SIZE, PAGE_SIZE); 301 p2m_mid_missing_mfn = extend_brk(PAGE_SIZE, PAGE_SIZE);
291 p2m_mid_mfn_init(p2m_mid_missing_mfn); 302 p2m_mid_mfn_init(p2m_mid_missing_mfn);
292 303
304 p2m_top_mfn_p = extend_brk(PAGE_SIZE, PAGE_SIZE);
305 p2m_top_mfn_p_init(p2m_top_mfn_p);
306
293 p2m_top_mfn = extend_brk(PAGE_SIZE, PAGE_SIZE); 307 p2m_top_mfn = extend_brk(PAGE_SIZE, PAGE_SIZE);
294 p2m_top_mfn_init(p2m_top_mfn); 308 p2m_top_mfn_init(p2m_top_mfn);
309 } else {
310 /* Reinitialise, mfn's all change after migration */
311 p2m_mid_mfn_init(p2m_mid_missing_mfn);
295 } 312 }
296 313
297 for (pfn = 0; pfn < xen_max_p2m_pfn; pfn += P2M_PER_PAGE) { 314 for (pfn = 0; pfn < xen_max_p2m_pfn; pfn += P2M_PER_PAGE) {
298 unsigned topidx = p2m_top_index(pfn); 315 unsigned topidx = p2m_top_index(pfn);
299 unsigned mididx = p2m_mid_index(pfn); 316 unsigned mididx = p2m_mid_index(pfn);
300 unsigned long **mid; 317 unsigned long **mid;
301 unsigned long mid_mfn;
302 unsigned long *mid_mfn_p; 318 unsigned long *mid_mfn_p;
303 319
304 mid = p2m_top[topidx]; 320 mid = p2m_top[topidx];
321 mid_mfn_p = p2m_top_mfn_p[topidx];
305 322
306 /* Don't bother allocating any mfn mid levels if 323 /* Don't bother allocating any mfn mid levels if
307 they're just missing */ 324 * they're just missing, just update the stored mfn,
308 if (mid[mididx] == p2m_missing) 325 * since all could have changed over a migrate.
326 */
327 if (mid == p2m_mid_missing) {
328 BUG_ON(mididx);
329 BUG_ON(mid_mfn_p != p2m_mid_missing_mfn);
330 p2m_top_mfn[topidx] = virt_to_mfn(p2m_mid_missing_mfn);
331 pfn += (P2M_MID_PER_PAGE - 1) * P2M_PER_PAGE;
309 continue; 332 continue;
310 333 }
311 mid_mfn = p2m_top_mfn[topidx];
312 mid_mfn_p = mfn_to_virt(mid_mfn);
313 334
314 if (mid_mfn_p == p2m_mid_missing_mfn) { 335 if (mid_mfn_p == p2m_mid_missing_mfn) {
315 /* 336 /*
@@ -321,11 +342,10 @@ void xen_build_mfn_list_list(void)
321 mid_mfn_p = extend_brk(PAGE_SIZE, PAGE_SIZE); 342 mid_mfn_p = extend_brk(PAGE_SIZE, PAGE_SIZE);
322 p2m_mid_mfn_init(mid_mfn_p); 343 p2m_mid_mfn_init(mid_mfn_p);
323 344
324 mid_mfn = virt_to_mfn(mid_mfn_p); 345 p2m_top_mfn_p[topidx] = mid_mfn_p;
325
326 p2m_top_mfn[topidx] = mid_mfn;
327 } 346 }
328 347
348 p2m_top_mfn[topidx] = virt_to_mfn(mid_mfn_p);
329 mid_mfn_p[mididx] = virt_to_mfn(mid[mididx]); 349 mid_mfn_p[mididx] = virt_to_mfn(mid[mididx]);
330 } 350 }
331} 351}
@@ -344,7 +364,7 @@ void __init xen_build_dynamic_phys_to_machine(void)
344{ 364{
345 unsigned long *mfn_list = (unsigned long *)xen_start_info->mfn_list; 365 unsigned long *mfn_list = (unsigned long *)xen_start_info->mfn_list;
346 unsigned long max_pfn = min(MAX_DOMAIN_PAGES, xen_start_info->nr_pages); 366 unsigned long max_pfn = min(MAX_DOMAIN_PAGES, xen_start_info->nr_pages);
347 unsigned pfn; 367 unsigned long pfn;
348 368
349 xen_max_p2m_pfn = max_pfn; 369 xen_max_p2m_pfn = max_pfn;
350 370
@@ -434,7 +454,9 @@ static bool alloc_p2m(unsigned long pfn)
434 } 454 }
435 455
436 top_mfn_p = &p2m_top_mfn[topidx]; 456 top_mfn_p = &p2m_top_mfn[topidx];
437 mid_mfn = mfn_to_virt(*top_mfn_p); 457 mid_mfn = p2m_top_mfn_p[topidx];
458
459 BUG_ON(virt_to_mfn(mid_mfn) != *top_mfn_p);
438 460
439 if (mid_mfn == p2m_mid_missing_mfn) { 461 if (mid_mfn == p2m_mid_missing_mfn) {
440 /* Separately check the mid mfn level */ 462 /* Separately check the mid mfn level */
@@ -446,11 +468,13 @@ static bool alloc_p2m(unsigned long pfn)
446 return false; 468 return false;
447 469
448 p2m_mid_mfn_init(mid_mfn); 470 p2m_mid_mfn_init(mid_mfn);
449 471
450 missing_mfn = virt_to_mfn(p2m_mid_missing_mfn); 472 missing_mfn = virt_to_mfn(p2m_mid_missing_mfn);
451 mid_mfn_mfn = virt_to_mfn(mid_mfn); 473 mid_mfn_mfn = virt_to_mfn(mid_mfn);
452 if (cmpxchg(top_mfn_p, missing_mfn, mid_mfn_mfn) != missing_mfn) 474 if (cmpxchg(top_mfn_p, missing_mfn, mid_mfn_mfn) != missing_mfn)
453 free_p2m_page(mid_mfn); 475 free_p2m_page(mid_mfn);
476 else
477 p2m_top_mfn_p[topidx] = mid_mfn;
454 } 478 }
455 479
456 if (p2m_top[topidx][mididx] == p2m_missing) { 480 if (p2m_top[topidx][mididx] == p2m_missing) {