aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen/gntdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/xen/gntdev.c')
-rw-r--r--drivers/xen/gntdev.c130
1 files changed, 88 insertions, 42 deletions
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index 2e22df2f7a3f..3c8803feba26 100644
--- a/drivers/xen/gntdev.c
+++ b/drivers/xen/gntdev.c
@@ -56,10 +56,15 @@ MODULE_PARM_DESC(limit, "Maximum number of grants that may be mapped by "
56static atomic_t pages_mapped = ATOMIC_INIT(0); 56static atomic_t pages_mapped = ATOMIC_INIT(0);
57 57
58static int use_ptemod; 58static int use_ptemod;
59#define populate_freeable_maps use_ptemod
59 60
60struct gntdev_priv { 61struct gntdev_priv {
62 /* maps with visible offsets in the file descriptor */
61 struct list_head maps; 63 struct list_head maps;
62 /* lock protects maps from concurrent changes */ 64 /* maps that are not visible; will be freed on munmap.
65 * Only populated if populate_freeable_maps == 1 */
66 struct list_head freeable_maps;
67 /* lock protects maps and freeable_maps */
63 spinlock_t lock; 68 spinlock_t lock;
64 struct mm_struct *mm; 69 struct mm_struct *mm;
65 struct mmu_notifier mn; 70 struct mmu_notifier mn;
@@ -193,7 +198,7 @@ static struct grant_map *gntdev_find_map_index(struct gntdev_priv *priv,
193 return NULL; 198 return NULL;
194} 199}
195 200
196static void gntdev_put_map(struct grant_map *map) 201static void gntdev_put_map(struct gntdev_priv *priv, struct grant_map *map)
197{ 202{
198 if (!map) 203 if (!map)
199 return; 204 return;
@@ -208,6 +213,12 @@ static void gntdev_put_map(struct grant_map *map)
208 evtchn_put(map->notify.event); 213 evtchn_put(map->notify.event);
209 } 214 }
210 215
216 if (populate_freeable_maps && priv) {
217 spin_lock(&priv->lock);
218 list_del(&map->next);
219 spin_unlock(&priv->lock);
220 }
221
211 if (map->pages && !use_ptemod) 222 if (map->pages && !use_ptemod)
212 unmap_grant_pages(map, 0, map->count); 223 unmap_grant_pages(map, 0, map->count);
213 gntdev_free_map(map); 224 gntdev_free_map(map);
@@ -301,17 +312,10 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int pages)
301 312
302 if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) { 313 if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) {
303 int pgno = (map->notify.addr >> PAGE_SHIFT); 314 int pgno = (map->notify.addr >> PAGE_SHIFT);
304 if (pgno >= offset && pgno < offset + pages && use_ptemod) { 315 if (pgno >= offset && pgno < offset + pages) {
305 void __user *tmp = (void __user *) 316 /* No need for kmap, pages are in lowmem */
306 map->vma->vm_start + map->notify.addr; 317 uint8_t *tmp = pfn_to_kaddr(page_to_pfn(map->pages[pgno]));
307 err = copy_to_user(tmp, &err, 1);
308 if (err)
309 return -EFAULT;
310 map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE;
311 } else if (pgno >= offset && pgno < offset + pages) {
312 uint8_t *tmp = kmap(map->pages[pgno]);
313 tmp[map->notify.addr & (PAGE_SIZE-1)] = 0; 318 tmp[map->notify.addr & (PAGE_SIZE-1)] = 0;
314 kunmap(map->pages[pgno]);
315 map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE; 319 map->notify.flags &= ~UNMAP_NOTIFY_CLEAR_BYTE;
316 } 320 }
317 } 321 }
@@ -376,11 +380,24 @@ static void gntdev_vma_open(struct vm_area_struct *vma)
376static void gntdev_vma_close(struct vm_area_struct *vma) 380static void gntdev_vma_close(struct vm_area_struct *vma)
377{ 381{
378 struct grant_map *map = vma->vm_private_data; 382 struct grant_map *map = vma->vm_private_data;
383 struct file *file = vma->vm_file;
384 struct gntdev_priv *priv = file->private_data;
379 385
380 pr_debug("gntdev_vma_close %p\n", vma); 386 pr_debug("gntdev_vma_close %p\n", vma);
381 map->vma = NULL; 387 if (use_ptemod) {
388 /* It is possible that an mmu notifier could be running
389 * concurrently, so take priv->lock to ensure that the vma won't
390 * vanishing during the unmap_grant_pages call, since we will
391 * spin here until that completes. Such a concurrent call will
392 * not do any unmapping, since that has been done prior to
393 * closing the vma, but it may still iterate the unmap_ops list.
394 */
395 spin_lock(&priv->lock);
396 map->vma = NULL;
397 spin_unlock(&priv->lock);
398 }
382 vma->vm_private_data = NULL; 399 vma->vm_private_data = NULL;
383 gntdev_put_map(map); 400 gntdev_put_map(priv, map);
384} 401}
385 402
386static struct vm_operations_struct gntdev_vmops = { 403static struct vm_operations_struct gntdev_vmops = {
@@ -390,33 +407,43 @@ static struct vm_operations_struct gntdev_vmops = {
390 407
391/* ------------------------------------------------------------------ */ 408/* ------------------------------------------------------------------ */
392 409
410static void unmap_if_in_range(struct grant_map *map,
411 unsigned long start, unsigned long end)
412{
413 unsigned long mstart, mend;
414 int err;
415
416 if (!map->vma)
417 return;
418 if (map->vma->vm_start >= end)
419 return;
420 if (map->vma->vm_end <= start)
421 return;
422 mstart = max(start, map->vma->vm_start);
423 mend = min(end, map->vma->vm_end);
424 pr_debug("map %d+%d (%lx %lx), range %lx %lx, mrange %lx %lx\n",
425 map->index, map->count,
426 map->vma->vm_start, map->vma->vm_end,
427 start, end, mstart, mend);
428 err = unmap_grant_pages(map,
429 (mstart - map->vma->vm_start) >> PAGE_SHIFT,
430 (mend - mstart) >> PAGE_SHIFT);
431 WARN_ON(err);
432}
433
393static void mn_invl_range_start(struct mmu_notifier *mn, 434static void mn_invl_range_start(struct mmu_notifier *mn,
394 struct mm_struct *mm, 435 struct mm_struct *mm,
395 unsigned long start, unsigned long end) 436 unsigned long start, unsigned long end)
396{ 437{
397 struct gntdev_priv *priv = container_of(mn, struct gntdev_priv, mn); 438 struct gntdev_priv *priv = container_of(mn, struct gntdev_priv, mn);
398 struct grant_map *map; 439 struct grant_map *map;
399 unsigned long mstart, mend;
400 int err;
401 440
402 spin_lock(&priv->lock); 441 spin_lock(&priv->lock);
403 list_for_each_entry(map, &priv->maps, next) { 442 list_for_each_entry(map, &priv->maps, next) {
404 if (!map->vma) 443 unmap_if_in_range(map, start, end);
405 continue; 444 }
406 if (map->vma->vm_start >= end) 445 list_for_each_entry(map, &priv->freeable_maps, next) {
407 continue; 446 unmap_if_in_range(map, start, end);
408 if (map->vma->vm_end <= start)
409 continue;
410 mstart = max(start, map->vma->vm_start);
411 mend = min(end, map->vma->vm_end);
412 pr_debug("map %d+%d (%lx %lx), range %lx %lx, mrange %lx %lx\n",
413 map->index, map->count,
414 map->vma->vm_start, map->vma->vm_end,
415 start, end, mstart, mend);
416 err = unmap_grant_pages(map,
417 (mstart - map->vma->vm_start) >> PAGE_SHIFT,
418 (mend - mstart) >> PAGE_SHIFT);
419 WARN_ON(err);
420 } 447 }
421 spin_unlock(&priv->lock); 448 spin_unlock(&priv->lock);
422} 449}
@@ -445,6 +472,15 @@ static void mn_release(struct mmu_notifier *mn,
445 err = unmap_grant_pages(map, /* offset */ 0, map->count); 472 err = unmap_grant_pages(map, /* offset */ 0, map->count);
446 WARN_ON(err); 473 WARN_ON(err);
447 } 474 }
475 list_for_each_entry(map, &priv->freeable_maps, next) {
476 if (!map->vma)
477 continue;
478 pr_debug("map %d+%d (%lx %lx)\n",
479 map->index, map->count,
480 map->vma->vm_start, map->vma->vm_end);
481 err = unmap_grant_pages(map, /* offset */ 0, map->count);
482 WARN_ON(err);
483 }
448 spin_unlock(&priv->lock); 484 spin_unlock(&priv->lock);
449} 485}
450 486
@@ -466,6 +502,7 @@ static int gntdev_open(struct inode *inode, struct file *flip)
466 return -ENOMEM; 502 return -ENOMEM;
467 503
468 INIT_LIST_HEAD(&priv->maps); 504 INIT_LIST_HEAD(&priv->maps);
505 INIT_LIST_HEAD(&priv->freeable_maps);
469 spin_lock_init(&priv->lock); 506 spin_lock_init(&priv->lock);
470 507
471 if (use_ptemod) { 508 if (use_ptemod) {
@@ -500,8 +537,9 @@ static int gntdev_release(struct inode *inode, struct file *flip)
500 while (!list_empty(&priv->maps)) { 537 while (!list_empty(&priv->maps)) {
501 map = list_entry(priv->maps.next, struct grant_map, next); 538 map = list_entry(priv->maps.next, struct grant_map, next);
502 list_del(&map->next); 539 list_del(&map->next);
503 gntdev_put_map(map); 540 gntdev_put_map(NULL /* already removed */, map);
504 } 541 }
542 WARN_ON(!list_empty(&priv->freeable_maps));
505 543
506 if (use_ptemod) 544 if (use_ptemod)
507 mmu_notifier_unregister(&priv->mn, priv->mm); 545 mmu_notifier_unregister(&priv->mn, priv->mm);
@@ -529,14 +567,14 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
529 567
530 if (unlikely(atomic_add_return(op.count, &pages_mapped) > limit)) { 568 if (unlikely(atomic_add_return(op.count, &pages_mapped) > limit)) {
531 pr_debug("can't map: over limit\n"); 569 pr_debug("can't map: over limit\n");
532 gntdev_put_map(map); 570 gntdev_put_map(NULL, map);
533 return err; 571 return err;
534 } 572 }
535 573
536 if (copy_from_user(map->grants, &u->refs, 574 if (copy_from_user(map->grants, &u->refs,
537 sizeof(map->grants[0]) * op.count) != 0) { 575 sizeof(map->grants[0]) * op.count) != 0) {
538 gntdev_put_map(map); 576 gntdev_put_map(NULL, map);
539 return err; 577 return -EFAULT;
540 } 578 }
541 579
542 spin_lock(&priv->lock); 580 spin_lock(&priv->lock);
@@ -565,11 +603,13 @@ static long gntdev_ioctl_unmap_grant_ref(struct gntdev_priv *priv,
565 map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count); 603 map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count);
566 if (map) { 604 if (map) {
567 list_del(&map->next); 605 list_del(&map->next);
606 if (populate_freeable_maps)
607 list_add_tail(&map->next, &priv->freeable_maps);
568 err = 0; 608 err = 0;
569 } 609 }
570 spin_unlock(&priv->lock); 610 spin_unlock(&priv->lock);
571 if (map) 611 if (map)
572 gntdev_put_map(map); 612 gntdev_put_map(priv, map);
573 return err; 613 return err;
574} 614}
575 615
@@ -579,25 +619,31 @@ static long gntdev_ioctl_get_offset_for_vaddr(struct gntdev_priv *priv,
579 struct ioctl_gntdev_get_offset_for_vaddr op; 619 struct ioctl_gntdev_get_offset_for_vaddr op;
580 struct vm_area_struct *vma; 620 struct vm_area_struct *vma;
581 struct grant_map *map; 621 struct grant_map *map;
622 int rv = -EINVAL;
582 623
583 if (copy_from_user(&op, u, sizeof(op)) != 0) 624 if (copy_from_user(&op, u, sizeof(op)) != 0)
584 return -EFAULT; 625 return -EFAULT;
585 pr_debug("priv %p, offset for vaddr %lx\n", priv, (unsigned long)op.vaddr); 626 pr_debug("priv %p, offset for vaddr %lx\n", priv, (unsigned long)op.vaddr);
586 627
628 down_read(&current->mm->mmap_sem);
587 vma = find_vma(current->mm, op.vaddr); 629 vma = find_vma(current->mm, op.vaddr);
588 if (!vma || vma->vm_ops != &gntdev_vmops) 630 if (!vma || vma->vm_ops != &gntdev_vmops)
589 return -EINVAL; 631 goto out_unlock;
590 632
591 map = vma->vm_private_data; 633 map = vma->vm_private_data;
592 if (!map) 634 if (!map)
593 return -EINVAL; 635 goto out_unlock;
594 636
595 op.offset = map->index << PAGE_SHIFT; 637 op.offset = map->index << PAGE_SHIFT;
596 op.count = map->count; 638 op.count = map->count;
639 rv = 0;
597 640
598 if (copy_to_user(u, &op, sizeof(op)) != 0) 641 out_unlock:
642 up_read(&current->mm->mmap_sem);
643
644 if (rv == 0 && copy_to_user(u, &op, sizeof(op)) != 0)
599 return -EFAULT; 645 return -EFAULT;
600 return 0; 646 return rv;
601} 647}
602 648
603static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u) 649static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
@@ -778,7 +824,7 @@ out_unlock_put:
778out_put_map: 824out_put_map:
779 if (use_ptemod) 825 if (use_ptemod)
780 map->vma = NULL; 826 map->vma = NULL;
781 gntdev_put_map(map); 827 gntdev_put_map(priv, map);
782 return err; 828 return err;
783} 829}
784 830