diff options
-rw-r--r-- | drivers/xen/gntdev.c | 67 |
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 | ||
63 | struct grant_map { | 63 | struct 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 | ||
170 | static int gntdev_del_map(struct grant_map *map) | 170 | static 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 | |||
185 | static 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 | ||
272 | static int gntdev_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | 263 | static 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; |