aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen
diff options
context:
space:
mode:
authorDaniel De Graaf <dgdegra@tycho.nsa.gov>2011-02-03 12:19:01 -0500
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2011-02-14 14:08:51 -0500
commit68b025c813c2eb41ff25628e3d4952d5185eb1a4 (patch)
tree94a35faa65ea9cf5956ee6eaa04ab65c7abb17ff /drivers/xen
parenta879211bf1d70339e429603805c014450c275f2a (diff)
xen-gntdev: Add reference counting to maps
This allows userspace to perform mmap() on the gntdev device and then immediately close the filehandle or remove the mapping using the remove ioctl, with the mapped area remaining valid until unmapped. This also fixes an infinite loop when a gntdev device is closed without first unmapping all areas. Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/xen')
-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 ce8c37c2b67..256162b5669 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;