diff options
author | Ian Campbell <ian.campbell@citrix.com> | 2010-10-21 06:00:46 -0400 |
---|---|---|
committer | Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> | 2010-10-22 15:57:36 -0400 |
commit | 375b2a9ada6d105483aab22f1af1d727bc3c418d (patch) | |
tree | 121f008f81d8424bdae575b8c2cad06c0dfd1a1f /arch | |
parent | cb52e6d9ed9bb9cf74f8396a603ecf12b64c1ec1 (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.c | 50 |
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 | ||
212 | static RESERVE_BRK_ARRAY(unsigned long **, p2m_top, P2M_TOP_PER_PAGE); | 214 | static RESERVE_BRK_ARRAY(unsigned long **, p2m_top, P2M_TOP_PER_PAGE); |
213 | static RESERVE_BRK_ARRAY(unsigned long, p2m_top_mfn, P2M_TOP_PER_PAGE); | 215 | static RESERVE_BRK_ARRAY(unsigned long, p2m_top_mfn, P2M_TOP_PER_PAGE); |
216 | static RESERVE_BRK_ARRAY(unsigned long *, p2m_top_mfn_p, P2M_TOP_PER_PAGE); | ||
214 | 217 | ||
215 | RESERVE_BRK(p2m_mid, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE))); | 218 | RESERVE_BRK(p2m_mid, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE))); |
216 | RESERVE_BRK(p2m_mid_mfn, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID_PER_PAGE))); | 219 | RESERVE_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 | ||
253 | static 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 | |||
250 | static void p2m_mid_init(unsigned long **mid) | 261 | static 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 | */ |
284 | void xen_build_mfn_list_list(void) | 295 | void 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) { |