diff options
Diffstat (limited to 'drivers/xen/gntdev.c')
-rw-r--r-- | drivers/xen/gntdev.c | 39 |
1 files changed, 34 insertions, 5 deletions
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index f914b26cf0c2..880798aae2f2 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,19 +117,22 @@ 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 | ||
126 | if (alloc_xenballooned_pages(count, add->pages)) | 129 | if (alloc_xenballooned_pages(count, add->pages, false /* lowmem */)) |
127 | goto err; | 130 | goto err; |
128 | 131 | ||
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 | ||
@@ -462,13 +492,11 @@ static int gntdev_release(struct inode *inode, struct file *flip) | |||
462 | 492 | ||
463 | pr_debug("priv %p\n", priv); | 493 | pr_debug("priv %p\n", priv); |
464 | 494 | ||
465 | spin_lock(&priv->lock); | ||
466 | while (!list_empty(&priv->maps)) { | 495 | while (!list_empty(&priv->maps)) { |
467 | map = list_entry(priv->maps.next, struct grant_map, next); | 496 | map = list_entry(priv->maps.next, struct grant_map, next); |
468 | list_del(&map->next); | 497 | list_del(&map->next); |
469 | gntdev_put_map(map); | 498 | gntdev_put_map(map); |
470 | } | 499 | } |
471 | spin_unlock(&priv->lock); | ||
472 | 500 | ||
473 | if (use_ptemod) | 501 | if (use_ptemod) |
474 | mmu_notifier_unregister(&priv->mn, priv->mm); | 502 | mmu_notifier_unregister(&priv->mn, priv->mm); |
@@ -532,10 +560,11 @@ static long gntdev_ioctl_unmap_grant_ref(struct gntdev_priv *priv, | |||
532 | map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count); | 560 | map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count); |
533 | if (map) { | 561 | if (map) { |
534 | list_del(&map->next); | 562 | list_del(&map->next); |
535 | gntdev_put_map(map); | ||
536 | err = 0; | 563 | err = 0; |
537 | } | 564 | } |
538 | spin_unlock(&priv->lock); | 565 | spin_unlock(&priv->lock); |
566 | if (map) | ||
567 | gntdev_put_map(map); | ||
539 | return err; | 568 | return err; |
540 | } | 569 | } |
541 | 570 | ||