diff options
Diffstat (limited to 'drivers/xen/gntdev.c')
-rw-r--r-- | drivers/xen/gntdev.c | 50 |
1 files changed, 39 insertions, 11 deletions
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index f914b26cf0c2..afca14d9042e 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 | ||
@@ -113,22 +114,25 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) | |||
113 | if (NULL == add) | 114 | if (NULL == add) |
114 | return NULL; | 115 | return NULL; |
115 | 116 | ||
116 | add->grants = kzalloc(sizeof(add->grants[0]) * count, GFP_KERNEL); | 117 | add->grants = kcalloc(count, sizeof(add->grants[0]), GFP_KERNEL); |
117 | add->map_ops = kzalloc(sizeof(add->map_ops[0]) * count, GFP_KERNEL); | 118 | add->map_ops = kcalloc(count, sizeof(add->map_ops[0]), GFP_KERNEL); |
118 | add->unmap_ops = kzalloc(sizeof(add->unmap_ops[0]) * count, GFP_KERNEL); | 119 | add->unmap_ops = kcalloc(count, sizeof(add->unmap_ops[0]), GFP_KERNEL); |
119 | add->pages = kzalloc(sizeof(add->pages[0]) * count, GFP_KERNEL); | 120 | add->kmap_ops = kcalloc(count, sizeof(add->kmap_ops[0]), GFP_KERNEL); |
121 | add->pages = kcalloc(count, sizeof(add->pages[0]), 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 | } |
@@ -188,9 +193,8 @@ static void gntdev_put_map(struct grant_map *map) | |||
188 | 193 | ||
189 | atomic_sub(map->count, &pages_mapped); | 194 | atomic_sub(map->count, &pages_mapped); |
190 | 195 | ||
191 | if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) { | 196 | if (map->notify.flags & UNMAP_NOTIFY_SEND_EVENT) |
192 | notify_remote_via_evtchn(map->notify.event); | 197 | notify_remote_via_evtchn(map->notify.event); |
193 | } | ||
194 | 198 | ||
195 | if (map->pages) { | 199 | if (map->pages) { |
196 | if (!use_ptemod) | 200 | if (!use_ptemod) |
@@ -243,10 +247,35 @@ static int map_grant_pages(struct grant_map *map) | |||
243 | gnttab_set_unmap_op(&map->unmap_ops[i], addr, | 247 | gnttab_set_unmap_op(&map->unmap_ops[i], addr, |
244 | map->flags, -1 /* handle */); | 248 | map->flags, -1 /* handle */); |
245 | } | 249 | } |
250 | } else { | ||
251 | /* | ||
252 | * Setup the map_ops corresponding to the pte entries pointing | ||
253 | * to the kernel linear addresses of the struct pages. | ||
254 | * These ptes are completely different from the user ptes dealt | ||
255 | * with find_grant_ptes. | ||
256 | */ | ||
257 | for (i = 0; i < map->count; i++) { | ||
258 | unsigned level; | ||
259 | unsigned long address = (unsigned long) | ||
260 | pfn_to_kaddr(page_to_pfn(map->pages[i])); | ||
261 | pte_t *ptep; | ||
262 | u64 pte_maddr = 0; | ||
263 | BUG_ON(PageHighMem(map->pages[i])); | ||
264 | |||
265 | ptep = lookup_address(address, &level); | ||
266 | pte_maddr = arbitrary_virt_to_machine(ptep).maddr; | ||
267 | gnttab_set_map_op(&map->kmap_ops[i], pte_maddr, | ||
268 | map->flags | | ||
269 | GNTMAP_host_map | | ||
270 | GNTMAP_contains_pte, | ||
271 | map->grants[i].ref, | ||
272 | map->grants[i].domid); | ||
273 | } | ||
246 | } | 274 | } |
247 | 275 | ||
248 | pr_debug("map %d+%d\n", map->index, map->count); | 276 | pr_debug("map %d+%d\n", map->index, map->count); |
249 | err = gnttab_map_refs(map->map_ops, map->pages, map->count); | 277 | err = gnttab_map_refs(map->map_ops, use_ptemod ? map->kmap_ops : NULL, |
278 | map->pages, map->count); | ||
250 | if (err) | 279 | if (err) |
251 | return err; | 280 | return err; |
252 | 281 | ||
@@ -462,13 +491,11 @@ static int gntdev_release(struct inode *inode, struct file *flip) | |||
462 | 491 | ||
463 | pr_debug("priv %p\n", priv); | 492 | pr_debug("priv %p\n", priv); |
464 | 493 | ||
465 | spin_lock(&priv->lock); | ||
466 | while (!list_empty(&priv->maps)) { | 494 | while (!list_empty(&priv->maps)) { |
467 | map = list_entry(priv->maps.next, struct grant_map, next); | 495 | map = list_entry(priv->maps.next, struct grant_map, next); |
468 | list_del(&map->next); | 496 | list_del(&map->next); |
469 | gntdev_put_map(map); | 497 | gntdev_put_map(map); |
470 | } | 498 | } |
471 | spin_unlock(&priv->lock); | ||
472 | 499 | ||
473 | if (use_ptemod) | 500 | if (use_ptemod) |
474 | mmu_notifier_unregister(&priv->mn, priv->mm); | 501 | mmu_notifier_unregister(&priv->mn, priv->mm); |
@@ -532,10 +559,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); | 559 | map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count); |
533 | if (map) { | 560 | if (map) { |
534 | list_del(&map->next); | 561 | list_del(&map->next); |
535 | gntdev_put_map(map); | ||
536 | err = 0; | 562 | err = 0; |
537 | } | 563 | } |
538 | spin_unlock(&priv->lock); | 564 | spin_unlock(&priv->lock); |
565 | if (map) | ||
566 | gntdev_put_map(map); | ||
539 | return err; | 567 | return err; |
540 | } | 568 | } |
541 | 569 | ||