aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>2010-12-13 09:42:30 -0500
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2011-01-11 14:32:14 -0500
commit87f1d40a706bdebdc8f959b9ac291d0d8fdfcc7e (patch)
tree9c05cb059c6eec2d85effd95642ee1a42b000fbe
parenta12b4eb34bb1ea16046c5b61e7a887e252cc1cce (diff)
xen p2m: clear the old pte when adding a page to m2p_override
When adding a page to m2p_override we change the p2m of the page so we need to also clear the old pte of the kernel linear mapping because it doesn't correspond anymore. When we remove the page from m2p_override we restore the original p2m of the page and we also restore the old pte of the kernel linear mapping. Before changing the p2m mappings in m2p_add_override and m2p_remove_override, check that the page passed as argument is valid and return an error if it is not. Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
-rw-r--r--arch/x86/include/asm/xen/page.h4
-rw-r--r--arch/x86/xen/p2m.c49
-rw-r--r--drivers/xen/grant-table.c16
3 files changed, 60 insertions, 9 deletions
diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
index 50f0a0f6bd6..f25bdf238a3 100644
--- a/arch/x86/include/asm/xen/page.h
+++ b/arch/x86/include/asm/xen/page.h
@@ -42,8 +42,8 @@ extern unsigned int machine_to_phys_order;
42extern unsigned long get_phys_to_machine(unsigned long pfn); 42extern unsigned long get_phys_to_machine(unsigned long pfn);
43extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn); 43extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
44 44
45extern void m2p_add_override(unsigned long mfn, struct page *page); 45extern int m2p_add_override(unsigned long mfn, struct page *page);
46extern void m2p_remove_override(struct page *page); 46extern int m2p_remove_override(struct page *page);
47extern struct page *m2p_find_override(unsigned long mfn); 47extern struct page *m2p_find_override(unsigned long mfn);
48extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn); 48extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn);
49 49
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
index b3b19d43b95..40d51225ff0 100644
--- a/arch/x86/xen/p2m.c
+++ b/arch/x86/xen/p2m.c
@@ -29,6 +29,7 @@
29#include <linux/module.h> 29#include <linux/module.h>
30#include <linux/list.h> 30#include <linux/list.h>
31#include <linux/hash.h> 31#include <linux/hash.h>
32#include <linux/sched.h>
32 33
33#include <asm/cache.h> 34#include <asm/cache.h>
34#include <asm/setup.h> 35#include <asm/setup.h>
@@ -404,34 +405,74 @@ static unsigned long mfn_hash(unsigned long mfn)
404} 405}
405 406
406/* Add an MFN override for a particular page */ 407/* Add an MFN override for a particular page */
407void m2p_add_override(unsigned long mfn, struct page *page) 408int m2p_add_override(unsigned long mfn, struct page *page)
408{ 409{
409 unsigned long flags; 410 unsigned long flags;
410 unsigned long pfn = page_to_pfn(page); 411 unsigned long pfn;
412 unsigned long address;
413 unsigned level;
414 pte_t *ptep = NULL;
415
416 pfn = page_to_pfn(page);
417 if (!PageHighMem(page)) {
418 address = (unsigned long)__va(pfn << PAGE_SHIFT);
419 ptep = lookup_address(address, &level);
420
421 if (WARN(ptep == NULL || level != PG_LEVEL_4K,
422 "m2p_add_override: pfn %lx not mapped", pfn))
423 return -EINVAL;
424 }
425
411 page->private = mfn; 426 page->private = mfn;
412 page->index = pfn_to_mfn(pfn); 427 page->index = pfn_to_mfn(pfn);
413 428
414 __set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)); 429 __set_phys_to_machine(pfn, FOREIGN_FRAME(mfn));
430 if (!PageHighMem(page))
431 /* Just zap old mapping for now */
432 pte_clear(&init_mm, address, ptep);
433
415 spin_lock_irqsave(&m2p_override_lock, flags); 434 spin_lock_irqsave(&m2p_override_lock, flags);
416 list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]); 435 list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]);
417 spin_unlock_irqrestore(&m2p_override_lock, flags); 436 spin_unlock_irqrestore(&m2p_override_lock, flags);
437
438 return 0;
418} 439}
419 440
420void m2p_remove_override(struct page *page) 441int m2p_remove_override(struct page *page)
421{ 442{
422 unsigned long flags; 443 unsigned long flags;
423 unsigned long mfn; 444 unsigned long mfn;
424 unsigned long pfn; 445 unsigned long pfn;
446 unsigned long address;
447 unsigned level;
448 pte_t *ptep = NULL;
425 449
426 pfn = page_to_pfn(page); 450 pfn = page_to_pfn(page);
427 mfn = get_phys_to_machine(pfn); 451 mfn = get_phys_to_machine(pfn);
428 if (mfn == INVALID_P2M_ENTRY || !(mfn & FOREIGN_FRAME_BIT)) 452 if (mfn == INVALID_P2M_ENTRY || !(mfn & FOREIGN_FRAME_BIT))
429 return; 453 return -EINVAL;
454
455 if (!PageHighMem(page)) {
456 address = (unsigned long)__va(pfn << PAGE_SHIFT);
457 ptep = lookup_address(address, &level);
458
459 if (WARN(ptep == NULL || level != PG_LEVEL_4K,
460 "m2p_remove_override: pfn %lx not mapped", pfn))
461 return -EINVAL;
462 }
430 463
431 spin_lock_irqsave(&m2p_override_lock, flags); 464 spin_lock_irqsave(&m2p_override_lock, flags);
432 list_del(&page->lru); 465 list_del(&page->lru);
433 spin_unlock_irqrestore(&m2p_override_lock, flags); 466 spin_unlock_irqrestore(&m2p_override_lock, flags);
434 __set_phys_to_machine(pfn, page->index); 467 __set_phys_to_machine(pfn, page->index);
468
469 if (!PageHighMem(page))
470 set_pte_at(&init_mm, address, ptep,
471 pfn_pte(pfn, PAGE_KERNEL));
472 /* No tlb flush necessary because the caller already
473 * left the pte unmapped. */
474
475 return 0;
435} 476}
436 477
437struct page *m2p_find_override(unsigned long mfn) 478struct page *m2p_find_override(unsigned long mfn)
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index 1afd5690858..9ef54ebc119 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -455,6 +455,8 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
455 unsigned long mfn; 455 unsigned long mfn;
456 456
457 ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map_ops, count); 457 ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map_ops, count);
458 if (ret)
459 return ret;
458 460
459 for (i = 0; i < count; i++) { 461 for (i = 0; i < count; i++) {
460 /* m2p override only supported for GNTMAP_contains_pte mappings */ 462 /* m2p override only supported for GNTMAP_contains_pte mappings */
@@ -463,7 +465,9 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
463 pte = (pte_t *) (mfn_to_virt(PFN_DOWN(map_ops[i].host_addr)) + 465 pte = (pte_t *) (mfn_to_virt(PFN_DOWN(map_ops[i].host_addr)) +
464 (map_ops[i].host_addr & ~PAGE_MASK)); 466 (map_ops[i].host_addr & ~PAGE_MASK));
465 mfn = pte_mfn(*pte); 467 mfn = pte_mfn(*pte);
466 m2p_add_override(mfn, pages[i]); 468 ret = m2p_add_override(mfn, pages[i]);
469 if (ret)
470 return ret;
467 } 471 }
468 472
469 return ret; 473 return ret;
@@ -476,8 +480,14 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
476 int i, ret; 480 int i, ret;
477 481
478 ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap_ops, count); 482 ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap_ops, count);
479 for (i = 0; i < count; i++) 483 if (ret)
480 m2p_remove_override(pages[i]); 484 return ret;
485
486 for (i = 0; i < count; i++) {
487 ret = m2p_remove_override(pages[i]);
488 if (ret)
489 return ret;
490 }
481 491
482 return ret; 492 return ret;
483} 493}