diff options
-rw-r--r-- | arch/x86/include/asm/xen/page.h | 4 | ||||
-rw-r--r-- | arch/x86/xen/p2m.c | 49 | ||||
-rw-r--r-- | drivers/xen/grant-table.c | 16 |
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; | |||
42 | extern unsigned long get_phys_to_machine(unsigned long pfn); | 42 | extern unsigned long get_phys_to_machine(unsigned long pfn); |
43 | extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn); | 43 | extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn); |
44 | 44 | ||
45 | extern void m2p_add_override(unsigned long mfn, struct page *page); | 45 | extern int m2p_add_override(unsigned long mfn, struct page *page); |
46 | extern void m2p_remove_override(struct page *page); | 46 | extern int m2p_remove_override(struct page *page); |
47 | extern struct page *m2p_find_override(unsigned long mfn); | 47 | extern struct page *m2p_find_override(unsigned long mfn); |
48 | extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn); | 48 | extern 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 */ |
407 | void m2p_add_override(unsigned long mfn, struct page *page) | 408 | int 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 | ||
420 | void m2p_remove_override(struct page *page) | 441 | int 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 | ||
437 | struct page *m2p_find_override(unsigned long mfn) | 478 | struct 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 | } |