diff options
-rw-r--r-- | arch/x86/include/asm/xen/page.h | 3 | ||||
-rw-r--r-- | arch/x86/xen/p2m.c | 76 | ||||
-rw-r--r-- | drivers/block/xen-blkback/blkback.c | 2 | ||||
-rw-r--r-- | drivers/xen/gntdev.c | 32 | ||||
-rw-r--r-- | drivers/xen/grant-table.c | 6 | ||||
-rw-r--r-- | include/xen/grant_table.h | 1 |
6 files changed, 104 insertions, 16 deletions
diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index bc12c12299c..3138d33b894 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <asm/pgtable.h> | 12 | #include <asm/pgtable.h> |
13 | 13 | ||
14 | #include <xen/interface/xen.h> | 14 | #include <xen/interface/xen.h> |
15 | #include <xen/grant_table.h> | ||
15 | #include <xen/features.h> | 16 | #include <xen/features.h> |
16 | 17 | ||
17 | /* Xen machine address */ | 18 | /* Xen machine address */ |
@@ -48,7 +49,7 @@ extern unsigned long set_phys_range_identity(unsigned long pfn_s, | |||
48 | unsigned long pfn_e); | 49 | unsigned long pfn_e); |
49 | 50 | ||
50 | extern int m2p_add_override(unsigned long mfn, struct page *page, | 51 | extern int m2p_add_override(unsigned long mfn, struct page *page, |
51 | bool clear_pte); | 52 | struct gnttab_map_grant_ref *kmap_op); |
52 | extern int m2p_remove_override(struct page *page, bool clear_pte); | 53 | extern int m2p_remove_override(struct page *page, bool clear_pte); |
53 | extern struct page *m2p_find_override(unsigned long mfn); | 54 | extern struct page *m2p_find_override(unsigned long mfn); |
54 | extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn); | 55 | extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn); |
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index 6e56b65edaf..a8ee9a45c35 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c | |||
@@ -161,7 +161,9 @@ | |||
161 | #include <asm/xen/page.h> | 161 | #include <asm/xen/page.h> |
162 | #include <asm/xen/hypercall.h> | 162 | #include <asm/xen/hypercall.h> |
163 | #include <asm/xen/hypervisor.h> | 163 | #include <asm/xen/hypervisor.h> |
164 | #include <xen/grant_table.h> | ||
164 | 165 | ||
166 | #include "multicalls.h" | ||
165 | #include "xen-ops.h" | 167 | #include "xen-ops.h" |
166 | 168 | ||
167 | static void __init m2p_override_init(void); | 169 | static void __init m2p_override_init(void); |
@@ -676,7 +678,8 @@ static unsigned long mfn_hash(unsigned long mfn) | |||
676 | } | 678 | } |
677 | 679 | ||
678 | /* Add an MFN override for a particular page */ | 680 | /* Add an MFN override for a particular page */ |
679 | int m2p_add_override(unsigned long mfn, struct page *page, bool clear_pte) | 681 | int m2p_add_override(unsigned long mfn, struct page *page, |
682 | struct gnttab_map_grant_ref *kmap_op) | ||
680 | { | 683 | { |
681 | unsigned long flags; | 684 | unsigned long flags; |
682 | unsigned long pfn; | 685 | unsigned long pfn; |
@@ -700,9 +703,20 @@ int m2p_add_override(unsigned long mfn, struct page *page, bool clear_pte) | |||
700 | if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)))) | 703 | if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)))) |
701 | return -ENOMEM; | 704 | return -ENOMEM; |
702 | 705 | ||
703 | if (clear_pte && !PageHighMem(page)) | 706 | if (kmap_op != NULL) { |
704 | /* Just zap old mapping for now */ | 707 | if (!PageHighMem(page)) { |
705 | pte_clear(&init_mm, address, ptep); | 708 | struct multicall_space mcs = |
709 | xen_mc_entry(sizeof(*kmap_op)); | ||
710 | |||
711 | MULTI_grant_table_op(mcs.mc, | ||
712 | GNTTABOP_map_grant_ref, kmap_op, 1); | ||
713 | |||
714 | xen_mc_issue(PARAVIRT_LAZY_MMU); | ||
715 | } | ||
716 | /* let's use dev_bus_addr to record the old mfn instead */ | ||
717 | kmap_op->dev_bus_addr = page->index; | ||
718 | page->index = (unsigned long) kmap_op; | ||
719 | } | ||
706 | spin_lock_irqsave(&m2p_override_lock, flags); | 720 | spin_lock_irqsave(&m2p_override_lock, flags); |
707 | list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]); | 721 | list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]); |
708 | spin_unlock_irqrestore(&m2p_override_lock, flags); | 722 | spin_unlock_irqrestore(&m2p_override_lock, flags); |
@@ -736,14 +750,56 @@ int m2p_remove_override(struct page *page, bool clear_pte) | |||
736 | spin_lock_irqsave(&m2p_override_lock, flags); | 750 | spin_lock_irqsave(&m2p_override_lock, flags); |
737 | list_del(&page->lru); | 751 | list_del(&page->lru); |
738 | spin_unlock_irqrestore(&m2p_override_lock, flags); | 752 | spin_unlock_irqrestore(&m2p_override_lock, flags); |
739 | set_phys_to_machine(pfn, page->index); | ||
740 | WARN_ON(!PagePrivate(page)); | 753 | WARN_ON(!PagePrivate(page)); |
741 | ClearPagePrivate(page); | 754 | ClearPagePrivate(page); |
742 | if (clear_pte && !PageHighMem(page)) | 755 | |
743 | set_pte_at(&init_mm, address, ptep, | 756 | if (clear_pte) { |
744 | pfn_pte(pfn, PAGE_KERNEL)); | 757 | struct gnttab_map_grant_ref *map_op = |
745 | /* No tlb flush necessary because the caller already | 758 | (struct gnttab_map_grant_ref *) page->index; |
746 | * left the pte unmapped. */ | 759 | set_phys_to_machine(pfn, map_op->dev_bus_addr); |
760 | if (!PageHighMem(page)) { | ||
761 | struct multicall_space mcs; | ||
762 | struct gnttab_unmap_grant_ref *unmap_op; | ||
763 | |||
764 | /* | ||
765 | * It might be that we queued all the m2p grant table | ||
766 | * hypercalls in a multicall, then m2p_remove_override | ||
767 | * get called before the multicall has actually been | ||
768 | * issued. In this case handle is going to -1 because | ||
769 | * it hasn't been modified yet. | ||
770 | */ | ||
771 | if (map_op->handle == -1) | ||
772 | xen_mc_flush(); | ||
773 | /* | ||
774 | * Now if map_op->handle is negative it means that the | ||
775 | * hypercall actually returned an error. | ||
776 | */ | ||
777 | if (map_op->handle == GNTST_general_error) { | ||
778 | printk(KERN_WARNING "m2p_remove_override: " | ||
779 | "pfn %lx mfn %lx, failed to modify kernel mappings", | ||
780 | pfn, mfn); | ||
781 | return -1; | ||
782 | } | ||
783 | |||
784 | mcs = xen_mc_entry( | ||
785 | sizeof(struct gnttab_unmap_grant_ref)); | ||
786 | unmap_op = mcs.args; | ||
787 | unmap_op->host_addr = map_op->host_addr; | ||
788 | unmap_op->handle = map_op->handle; | ||
789 | unmap_op->dev_bus_addr = 0; | ||
790 | |||
791 | MULTI_grant_table_op(mcs.mc, | ||
792 | GNTTABOP_unmap_grant_ref, unmap_op, 1); | ||
793 | |||
794 | xen_mc_issue(PARAVIRT_LAZY_MMU); | ||
795 | |||
796 | set_pte_at(&init_mm, address, ptep, | ||
797 | pfn_pte(pfn, PAGE_KERNEL)); | ||
798 | __flush_tlb_single(address); | ||
799 | map_op->host_addr = 0; | ||
800 | } | ||
801 | } else | ||
802 | set_phys_to_machine(pfn, page->index); | ||
747 | 803 | ||
748 | return 0; | 804 | return 0; |
749 | } | 805 | } |
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 2330a9ad5e9..1540792b1e5 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c | |||
@@ -396,7 +396,7 @@ static int xen_blkbk_map(struct blkif_request *req, | |||
396 | continue; | 396 | continue; |
397 | 397 | ||
398 | ret = m2p_add_override(PFN_DOWN(map[i].dev_bus_addr), | 398 | ret = m2p_add_override(PFN_DOWN(map[i].dev_bus_addr), |
399 | blkbk->pending_page(pending_req, i), false); | 399 | blkbk->pending_page(pending_req, i), NULL); |
400 | if (ret) { | 400 | if (ret) { |
401 | pr_alert(DRV_PFX "Failed to install M2P override for %lx (ret: %d)\n", | 401 | pr_alert(DRV_PFX "Failed to install M2P override for %lx (ret: %d)\n", |
402 | (unsigned long)map[i].dev_bus_addr, ret); | 402 | (unsigned long)map[i].dev_bus_addr, ret); |
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 7b9b1d1b75a..3e3603f3524 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c | |||
@@ -83,6 +83,7 @@ struct grant_map { | |||
83 | struct ioctl_gntdev_grant_ref *grants; | 83 | struct ioctl_gntdev_grant_ref *grants; |
84 | struct gnttab_map_grant_ref *map_ops; | 84 | struct gnttab_map_grant_ref *map_ops; |
85 | struct gnttab_unmap_grant_ref *unmap_ops; | 85 | struct gnttab_unmap_grant_ref *unmap_ops; |
86 | struct gnttab_map_grant_ref *kmap_ops; | ||
86 | struct page **pages; | 87 | struct page **pages; |
87 | }; | 88 | }; |
88 | 89 | ||
@@ -116,10 +117,12 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) | |||
116 | add->grants = kzalloc(sizeof(add->grants[0]) * count, GFP_KERNEL); | 117 | add->grants = kzalloc(sizeof(add->grants[0]) * count, GFP_KERNEL); |
117 | add->map_ops = kzalloc(sizeof(add->map_ops[0]) * count, GFP_KERNEL); | 118 | add->map_ops = kzalloc(sizeof(add->map_ops[0]) * count, GFP_KERNEL); |
118 | add->unmap_ops = kzalloc(sizeof(add->unmap_ops[0]) * count, GFP_KERNEL); | 119 | add->unmap_ops = kzalloc(sizeof(add->unmap_ops[0]) * count, GFP_KERNEL); |
120 | add->kmap_ops = kzalloc(sizeof(add->kmap_ops[0]) * count, GFP_KERNEL); | ||
119 | add->pages = kzalloc(sizeof(add->pages[0]) * count, GFP_KERNEL); | 121 | add->pages = kzalloc(sizeof(add->pages[0]) * count, GFP_KERNEL); |
120 | if (NULL == add->grants || | 122 | if (NULL == add->grants || |
121 | NULL == add->map_ops || | 123 | NULL == add->map_ops || |
122 | NULL == add->unmap_ops || | 124 | NULL == add->unmap_ops || |
125 | NULL == add->kmap_ops || | ||
123 | NULL == add->pages) | 126 | NULL == add->pages) |
124 | goto err; | 127 | goto err; |
125 | 128 | ||
@@ -129,6 +132,7 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) | |||
129 | for (i = 0; i < count; i++) { | 132 | for (i = 0; i < count; i++) { |
130 | add->map_ops[i].handle = -1; | 133 | add->map_ops[i].handle = -1; |
131 | add->unmap_ops[i].handle = -1; | 134 | add->unmap_ops[i].handle = -1; |
135 | add->kmap_ops[i].handle = -1; | ||
132 | } | 136 | } |
133 | 137 | ||
134 | add->index = 0; | 138 | add->index = 0; |
@@ -142,6 +146,7 @@ err: | |||
142 | kfree(add->grants); | 146 | kfree(add->grants); |
143 | kfree(add->map_ops); | 147 | kfree(add->map_ops); |
144 | kfree(add->unmap_ops); | 148 | kfree(add->unmap_ops); |
149 | kfree(add->kmap_ops); | ||
145 | kfree(add); | 150 | kfree(add); |
146 | return NULL; | 151 | return NULL; |
147 | } | 152 | } |
@@ -243,10 +248,35 @@ static int map_grant_pages(struct grant_map *map) | |||
243 | gnttab_set_unmap_op(&map->unmap_ops[i], addr, | 248 | gnttab_set_unmap_op(&map->unmap_ops[i], addr, |
244 | map->flags, -1 /* handle */); | 249 | map->flags, -1 /* handle */); |
245 | } | 250 | } |
251 | } else { | ||
252 | /* | ||
253 | * Setup the map_ops corresponding to the pte entries pointing | ||
254 | * to the kernel linear addresses of the struct pages. | ||
255 | * These ptes are completely different from the user ptes dealt | ||
256 | * with find_grant_ptes. | ||
257 | */ | ||
258 | for (i = 0; i < map->count; i++) { | ||
259 | unsigned level; | ||
260 | unsigned long address = (unsigned long) | ||
261 | pfn_to_kaddr(page_to_pfn(map->pages[i])); | ||
262 | pte_t *ptep; | ||
263 | u64 pte_maddr = 0; | ||
264 | BUG_ON(PageHighMem(map->pages[i])); | ||
265 | |||
266 | ptep = lookup_address(address, &level); | ||
267 | pte_maddr = arbitrary_virt_to_machine(ptep).maddr; | ||
268 | gnttab_set_map_op(&map->kmap_ops[i], pte_maddr, | ||
269 | map->flags | | ||
270 | GNTMAP_host_map | | ||
271 | GNTMAP_contains_pte, | ||
272 | map->grants[i].ref, | ||
273 | map->grants[i].domid); | ||
274 | } | ||
246 | } | 275 | } |
247 | 276 | ||
248 | pr_debug("map %d+%d\n", map->index, map->count); | 277 | pr_debug("map %d+%d\n", map->index, map->count); |
249 | err = gnttab_map_refs(map->map_ops, map->pages, map->count); | 278 | err = gnttab_map_refs(map->map_ops, use_ptemod ? map->kmap_ops : NULL, |
279 | map->pages, map->count); | ||
250 | if (err) | 280 | if (err) |
251 | return err; | 281 | return err; |
252 | 282 | ||
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index 4f44b347b24..8c71ab80175 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c | |||
@@ -448,7 +448,8 @@ unsigned int gnttab_max_grant_frames(void) | |||
448 | EXPORT_SYMBOL_GPL(gnttab_max_grant_frames); | 448 | EXPORT_SYMBOL_GPL(gnttab_max_grant_frames); |
449 | 449 | ||
450 | int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, | 450 | int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, |
451 | struct page **pages, unsigned int count) | 451 | struct gnttab_map_grant_ref *kmap_ops, |
452 | struct page **pages, unsigned int count) | ||
452 | { | 453 | { |
453 | int i, ret; | 454 | int i, ret; |
454 | pte_t *pte; | 455 | pte_t *pte; |
@@ -488,8 +489,7 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, | |||
488 | */ | 489 | */ |
489 | return -EOPNOTSUPP; | 490 | return -EOPNOTSUPP; |
490 | } | 491 | } |
491 | ret = m2p_add_override(mfn, pages[i], | 492 | ret = m2p_add_override(mfn, pages[i], &kmap_ops[i]); |
492 | map_ops[i].flags & GNTMAP_contains_pte); | ||
493 | if (ret) | 493 | if (ret) |
494 | return ret; | 494 | return ret; |
495 | } | 495 | } |
diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h index b1fab6b5b3e..6b99bfbd785 100644 --- a/include/xen/grant_table.h +++ b/include/xen/grant_table.h | |||
@@ -156,6 +156,7 @@ unsigned int gnttab_max_grant_frames(void); | |||
156 | #define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr)) | 156 | #define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr)) |
157 | 157 | ||
158 | int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, | 158 | int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, |
159 | struct gnttab_map_grant_ref *kmap_ops, | ||
159 | struct page **pages, unsigned int count); | 160 | struct page **pages, unsigned int count); |
160 | int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, | 161 | int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, |
161 | struct page **pages, unsigned int count); | 162 | struct page **pages, unsigned int count); |