diff options
Diffstat (limited to 'drivers/xen/xenbus/xenbus_client.c')
-rw-r--r-- | drivers/xen/xenbus/xenbus_client.c | 130 |
1 files changed, 67 insertions, 63 deletions
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c index 82a8866758ee..a1c17000129b 100644 --- a/drivers/xen/xenbus/xenbus_client.c +++ b/drivers/xen/xenbus/xenbus_client.c | |||
@@ -519,64 +519,6 @@ static int __xenbus_map_ring(struct xenbus_device *dev, | |||
519 | return err; | 519 | return err; |
520 | } | 520 | } |
521 | 521 | ||
522 | static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev, | ||
523 | grant_ref_t *gnt_refs, | ||
524 | unsigned int nr_grefs, | ||
525 | void **vaddr) | ||
526 | { | ||
527 | struct xenbus_map_node *node; | ||
528 | struct vm_struct *area; | ||
529 | pte_t *ptes[XENBUS_MAX_RING_GRANTS]; | ||
530 | phys_addr_t phys_addrs[XENBUS_MAX_RING_GRANTS]; | ||
531 | int err = GNTST_okay; | ||
532 | int i; | ||
533 | bool leaked; | ||
534 | |||
535 | *vaddr = NULL; | ||
536 | |||
537 | if (nr_grefs > XENBUS_MAX_RING_GRANTS) | ||
538 | return -EINVAL; | ||
539 | |||
540 | node = kzalloc(sizeof(*node), GFP_KERNEL); | ||
541 | if (!node) | ||
542 | return -ENOMEM; | ||
543 | |||
544 | area = alloc_vm_area(XEN_PAGE_SIZE * nr_grefs, ptes); | ||
545 | if (!area) { | ||
546 | kfree(node); | ||
547 | return -ENOMEM; | ||
548 | } | ||
549 | |||
550 | for (i = 0; i < nr_grefs; i++) | ||
551 | phys_addrs[i] = arbitrary_virt_to_machine(ptes[i]).maddr; | ||
552 | |||
553 | err = __xenbus_map_ring(dev, gnt_refs, nr_grefs, node->handles, | ||
554 | phys_addrs, | ||
555 | GNTMAP_host_map | GNTMAP_contains_pte, | ||
556 | &leaked); | ||
557 | if (err) | ||
558 | goto failed; | ||
559 | |||
560 | node->nr_handles = nr_grefs; | ||
561 | node->pv.area = area; | ||
562 | |||
563 | spin_lock(&xenbus_valloc_lock); | ||
564 | list_add(&node->next, &xenbus_valloc_pages); | ||
565 | spin_unlock(&xenbus_valloc_lock); | ||
566 | |||
567 | *vaddr = area->addr; | ||
568 | return 0; | ||
569 | |||
570 | failed: | ||
571 | if (!leaked) | ||
572 | free_vm_area(area); | ||
573 | else | ||
574 | pr_alert("leaking VM area %p size %u page(s)", area, nr_grefs); | ||
575 | |||
576 | kfree(node); | ||
577 | return err; | ||
578 | } | ||
579 | |||
580 | struct map_ring_valloc_hvm | 522 | struct map_ring_valloc_hvm |
581 | { | 523 | { |
582 | unsigned int idx; | 524 | unsigned int idx; |
@@ -725,6 +667,65 @@ int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr) | |||
725 | } | 667 | } |
726 | EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree); | 668 | EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree); |
727 | 669 | ||
670 | #ifdef CONFIG_XEN_PV | ||
671 | static int xenbus_map_ring_valloc_pv(struct xenbus_device *dev, | ||
672 | grant_ref_t *gnt_refs, | ||
673 | unsigned int nr_grefs, | ||
674 | void **vaddr) | ||
675 | { | ||
676 | struct xenbus_map_node *node; | ||
677 | struct vm_struct *area; | ||
678 | pte_t *ptes[XENBUS_MAX_RING_GRANTS]; | ||
679 | phys_addr_t phys_addrs[XENBUS_MAX_RING_GRANTS]; | ||
680 | int err = GNTST_okay; | ||
681 | int i; | ||
682 | bool leaked; | ||
683 | |||
684 | *vaddr = NULL; | ||
685 | |||
686 | if (nr_grefs > XENBUS_MAX_RING_GRANTS) | ||
687 | return -EINVAL; | ||
688 | |||
689 | node = kzalloc(sizeof(*node), GFP_KERNEL); | ||
690 | if (!node) | ||
691 | return -ENOMEM; | ||
692 | |||
693 | area = alloc_vm_area(XEN_PAGE_SIZE * nr_grefs, ptes); | ||
694 | if (!area) { | ||
695 | kfree(node); | ||
696 | return -ENOMEM; | ||
697 | } | ||
698 | |||
699 | for (i = 0; i < nr_grefs; i++) | ||
700 | phys_addrs[i] = arbitrary_virt_to_machine(ptes[i]).maddr; | ||
701 | |||
702 | err = __xenbus_map_ring(dev, gnt_refs, nr_grefs, node->handles, | ||
703 | phys_addrs, | ||
704 | GNTMAP_host_map | GNTMAP_contains_pte, | ||
705 | &leaked); | ||
706 | if (err) | ||
707 | goto failed; | ||
708 | |||
709 | node->nr_handles = nr_grefs; | ||
710 | node->pv.area = area; | ||
711 | |||
712 | spin_lock(&xenbus_valloc_lock); | ||
713 | list_add(&node->next, &xenbus_valloc_pages); | ||
714 | spin_unlock(&xenbus_valloc_lock); | ||
715 | |||
716 | *vaddr = area->addr; | ||
717 | return 0; | ||
718 | |||
719 | failed: | ||
720 | if (!leaked) | ||
721 | free_vm_area(area); | ||
722 | else | ||
723 | pr_alert("leaking VM area %p size %u page(s)", area, nr_grefs); | ||
724 | |||
725 | kfree(node); | ||
726 | return err; | ||
727 | } | ||
728 | |||
728 | static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr) | 729 | static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr) |
729 | { | 730 | { |
730 | struct xenbus_map_node *node; | 731 | struct xenbus_map_node *node; |
@@ -788,6 +789,12 @@ static int xenbus_unmap_ring_vfree_pv(struct xenbus_device *dev, void *vaddr) | |||
788 | return err; | 789 | return err; |
789 | } | 790 | } |
790 | 791 | ||
792 | static const struct xenbus_ring_ops ring_ops_pv = { | ||
793 | .map = xenbus_map_ring_valloc_pv, | ||
794 | .unmap = xenbus_unmap_ring_vfree_pv, | ||
795 | }; | ||
796 | #endif | ||
797 | |||
791 | struct unmap_ring_vfree_hvm | 798 | struct unmap_ring_vfree_hvm |
792 | { | 799 | { |
793 | unsigned int idx; | 800 | unsigned int idx; |
@@ -916,11 +923,6 @@ enum xenbus_state xenbus_read_driver_state(const char *path) | |||
916 | } | 923 | } |
917 | EXPORT_SYMBOL_GPL(xenbus_read_driver_state); | 924 | EXPORT_SYMBOL_GPL(xenbus_read_driver_state); |
918 | 925 | ||
919 | static const struct xenbus_ring_ops ring_ops_pv = { | ||
920 | .map = xenbus_map_ring_valloc_pv, | ||
921 | .unmap = xenbus_unmap_ring_vfree_pv, | ||
922 | }; | ||
923 | |||
924 | static const struct xenbus_ring_ops ring_ops_hvm = { | 926 | static const struct xenbus_ring_ops ring_ops_hvm = { |
925 | .map = xenbus_map_ring_valloc_hvm, | 927 | .map = xenbus_map_ring_valloc_hvm, |
926 | .unmap = xenbus_unmap_ring_vfree_hvm, | 928 | .unmap = xenbus_unmap_ring_vfree_hvm, |
@@ -928,8 +930,10 @@ static const struct xenbus_ring_ops ring_ops_hvm = { | |||
928 | 930 | ||
929 | void __init xenbus_ring_ops_init(void) | 931 | void __init xenbus_ring_ops_init(void) |
930 | { | 932 | { |
933 | #ifdef CONFIG_XEN_PV | ||
931 | if (!xen_feature(XENFEAT_auto_translated_physmap)) | 934 | if (!xen_feature(XENFEAT_auto_translated_physmap)) |
932 | ring_ops = &ring_ops_pv; | 935 | ring_ops = &ring_ops_pv; |
933 | else | 936 | else |
937 | #endif | ||
934 | ring_ops = &ring_ops_hvm; | 938 | ring_ops = &ring_ops_hvm; |
935 | } | 939 | } |