aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/xen/gntdev.c67
1 files changed, 27 insertions, 40 deletions
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index ce8c37c2b673..256162b56691 100644
--- a/drivers/xen/gntdev.c
+++ b/drivers/xen/gntdev.c
@@ -62,12 +62,12 @@ struct gntdev_priv {
62 62
63struct grant_map { 63struct grant_map {
64 struct list_head next; 64 struct list_head next;
65 struct gntdev_priv *priv;
66 struct vm_area_struct *vma; 65 struct vm_area_struct *vma;
67 int index; 66 int index;
68 int count; 67 int count;
69 int flags; 68 int flags;
70 int is_mapped; 69 int is_mapped;
70 atomic_t users;
71 struct ioctl_gntdev_grant_ref *grants; 71 struct ioctl_gntdev_grant_ref *grants;
72 struct gnttab_map_grant_ref *map_ops; 72 struct gnttab_map_grant_ref *map_ops;
73 struct gnttab_unmap_grant_ref *unmap_ops; 73 struct gnttab_unmap_grant_ref *unmap_ops;
@@ -117,7 +117,7 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count)
117 117
118 add->index = 0; 118 add->index = 0;
119 add->count = count; 119 add->count = count;
120 add->priv = priv; 120 atomic_set(&add->users, 1);
121 121
122 return add; 122 return add;
123 123
@@ -167,28 +167,18 @@ static struct grant_map *gntdev_find_map_index(struct gntdev_priv *priv,
167 return NULL; 167 return NULL;
168} 168}
169 169
170static int gntdev_del_map(struct grant_map *map) 170static void gntdev_put_map(struct grant_map *map)
171{
172 int i;
173
174 if (map->vma)
175 return -EBUSY;
176 for (i = 0; i < map->count; i++)
177 if (map->unmap_ops[i].handle)
178 return -EBUSY;
179
180 atomic_sub(map->count, &pages_mapped);
181 list_del(&map->next);
182 return 0;
183}
184
185static void gntdev_free_map(struct grant_map *map)
186{ 171{
187 int i; 172 int i;
188 173
189 if (!map) 174 if (!map)
190 return; 175 return;
191 176
177 if (!atomic_dec_and_test(&map->users))
178 return;
179
180 atomic_sub(map->count, &pages_mapped);
181
192 if (map->pages) 182 if (map->pages)
193 for (i = 0; i < map->count; i++) { 183 for (i = 0; i < map->count; i++) {
194 if (map->pages[i]) 184 if (map->pages[i])
@@ -267,6 +257,7 @@ static void gntdev_vma_close(struct vm_area_struct *vma)
267 map->is_mapped = 0; 257 map->is_mapped = 0;
268 map->vma = NULL; 258 map->vma = NULL;
269 vma->vm_private_data = NULL; 259 vma->vm_private_data = NULL;
260 gntdev_put_map(map);
270} 261}
271 262
272static int gntdev_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 263static int gntdev_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
@@ -388,17 +379,14 @@ static int gntdev_release(struct inode *inode, struct file *flip)
388{ 379{
389 struct gntdev_priv *priv = flip->private_data; 380 struct gntdev_priv *priv = flip->private_data;
390 struct grant_map *map; 381 struct grant_map *map;
391 int err;
392 382
393 pr_debug("priv %p\n", priv); 383 pr_debug("priv %p\n", priv);
394 384
395 spin_lock(&priv->lock); 385 spin_lock(&priv->lock);
396 while (!list_empty(&priv->maps)) { 386 while (!list_empty(&priv->maps)) {
397 map = list_entry(priv->maps.next, struct grant_map, next); 387 map = list_entry(priv->maps.next, struct grant_map, next);
398 err = gntdev_del_map(map); 388 list_del(&map->next);
399 if (WARN_ON(err)) 389 gntdev_put_map(map);
400 gntdev_free_map(map);
401
402 } 390 }
403 spin_unlock(&priv->lock); 391 spin_unlock(&priv->lock);
404 392
@@ -425,15 +413,15 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
425 if (!map) 413 if (!map)
426 return err; 414 return err;
427 415
428 if (copy_from_user(map->grants, &u->refs, 416 if (unlikely(atomic_add_return(op.count, &pages_mapped) > limit)) {
429 sizeof(map->grants[0]) * op.count) != 0) { 417 pr_debug("can't map: over limit\n");
430 gntdev_free_map(map); 418 gntdev_put_map(map);
431 return err; 419 return err;
432 } 420 }
433 421
434 if (unlikely(atomic_add_return(op.count, &pages_mapped) > limit)) { 422 if (copy_from_user(map->grants, &u->refs,
435 pr_debug("can't map: over limit\n"); 423 sizeof(map->grants[0]) * op.count) != 0) {
436 gntdev_free_map(map); 424 gntdev_put_map(map);
437 return err; 425 return err;
438 } 426 }
439 427
@@ -442,13 +430,9 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
442 op.index = map->index << PAGE_SHIFT; 430 op.index = map->index << PAGE_SHIFT;
443 spin_unlock(&priv->lock); 431 spin_unlock(&priv->lock);
444 432
445 if (copy_to_user(u, &op, sizeof(op)) != 0) { 433 if (copy_to_user(u, &op, sizeof(op)) != 0)
446 spin_lock(&priv->lock); 434 return -EFAULT;
447 gntdev_del_map(map); 435
448 spin_unlock(&priv->lock);
449 gntdev_free_map(map);
450 return err;
451 }
452 return 0; 436 return 0;
453} 437}
454 438
@@ -465,11 +449,12 @@ static long gntdev_ioctl_unmap_grant_ref(struct gntdev_priv *priv,
465 449
466 spin_lock(&priv->lock); 450 spin_lock(&priv->lock);
467 map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count); 451 map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count);
468 if (map) 452 if (map) {
469 err = gntdev_del_map(map); 453 list_del(&map->next);
454 gntdev_put_map(map);
455 err = 0;
456 }
470 spin_unlock(&priv->lock); 457 spin_unlock(&priv->lock);
471 if (!err)
472 gntdev_free_map(map);
473 return err; 458 return err;
474} 459}
475 460
@@ -549,6 +534,8 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma)
549 goto unlock_out; 534 goto unlock_out;
550 } 535 }
551 536
537 atomic_inc(&map->users);
538
552 vma->vm_ops = &gntdev_vmops; 539 vma->vm_ops = &gntdev_vmops;
553 540
554 vma->vm_flags |= VM_RESERVED|VM_DONTCOPY|VM_DONTEXPAND|VM_PFNMAP; 541 vma->vm_flags |= VM_RESERVED|VM_DONTCOPY|VM_DONTEXPAND|VM_PFNMAP;