aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/xen/page.h3
-rw-r--r--arch/x86/xen/p2m.c76
-rw-r--r--drivers/block/xen-blkback/blkback.c2
-rw-r--r--drivers/xen/gntdev.c32
-rw-r--r--drivers/xen/grant-table.c6
-rw-r--r--include/xen/grant_table.h1
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
50extern int m2p_add_override(unsigned long mfn, struct page *page, 51extern int m2p_add_override(unsigned long mfn, struct page *page,
51 bool clear_pte); 52 struct gnttab_map_grant_ref *kmap_op);
52extern int m2p_remove_override(struct page *page, bool clear_pte); 53extern int m2p_remove_override(struct page *page, bool clear_pte);
53extern struct page *m2p_find_override(unsigned long mfn); 54extern struct page *m2p_find_override(unsigned long mfn);
54extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn); 55extern 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
167static void __init m2p_override_init(void); 169static 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 */
679int m2p_add_override(unsigned long mfn, struct page *page, bool clear_pte) 681int 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)
448EXPORT_SYMBOL_GPL(gnttab_max_grant_frames); 448EXPORT_SYMBOL_GPL(gnttab_max_grant_frames);
449 449
450int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, 450int 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
158int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, 158int 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);
160int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, 161int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
161 struct page **pages, unsigned int count); 162 struct page **pages, unsigned int count);