aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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}