diff options
| -rw-r--r-- | drivers/infiniband/core/uverbs.h | 26 | ||||
| -rw-r--r-- | drivers/infiniband/core/uverbs_cmd.c | 155 | ||||
| -rw-r--r-- | drivers/infiniband/core/uverbs_main.c | 98 | ||||
| -rw-r--r-- | include/rdma/ib_user_verbs.h | 21 |
4 files changed, 211 insertions, 89 deletions
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 180b3d4765e4..b1897bed14ad 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h | |||
| @@ -76,20 +76,28 @@ struct ib_uverbs_file { | |||
| 76 | struct ib_uverbs_event_file comp_file[1]; | 76 | struct ib_uverbs_event_file comp_file[1]; |
| 77 | }; | 77 | }; |
| 78 | 78 | ||
| 79 | struct ib_uverbs_async_event { | 79 | struct ib_uverbs_event { |
| 80 | struct ib_uverbs_async_event_desc desc; | 80 | union { |
| 81 | struct ib_uverbs_async_event_desc async; | ||
| 82 | struct ib_uverbs_comp_event_desc comp; | ||
| 83 | } desc; | ||
| 81 | struct list_head list; | 84 | struct list_head list; |
| 85 | struct list_head obj_list; | ||
| 86 | u32 *counter; | ||
| 82 | }; | 87 | }; |
| 83 | 88 | ||
| 84 | struct ib_uverbs_comp_event { | 89 | struct ib_uevent_object { |
| 85 | struct ib_uverbs_comp_event_desc desc; | 90 | struct ib_uobject uobject; |
| 86 | struct list_head list; | 91 | struct list_head event_list; |
| 92 | u32 events_reported; | ||
| 87 | }; | 93 | }; |
| 88 | 94 | ||
| 89 | struct ib_uobject_mr { | 95 | struct ib_ucq_object { |
| 90 | struct ib_uobject uobj; | 96 | struct ib_uobject uobject; |
| 91 | struct page *page_list; | 97 | struct list_head comp_list; |
| 92 | struct scatterlist *sg_list; | 98 | struct list_head async_list; |
| 99 | u32 comp_events_reported; | ||
| 100 | u32 async_events_reported; | ||
| 93 | }; | 101 | }; |
| 94 | 102 | ||
| 95 | extern struct semaphore ib_uverbs_idr_mutex; | 103 | extern struct semaphore ib_uverbs_idr_mutex; |
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index ebccf9f38af9..e91ebde46481 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c | |||
| @@ -590,7 +590,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, | |||
| 590 | struct ib_uverbs_create_cq cmd; | 590 | struct ib_uverbs_create_cq cmd; |
| 591 | struct ib_uverbs_create_cq_resp resp; | 591 | struct ib_uverbs_create_cq_resp resp; |
| 592 | struct ib_udata udata; | 592 | struct ib_udata udata; |
| 593 | struct ib_uobject *uobj; | 593 | struct ib_ucq_object *uobj; |
| 594 | struct ib_cq *cq; | 594 | struct ib_cq *cq; |
| 595 | int ret; | 595 | int ret; |
| 596 | 596 | ||
| @@ -611,8 +611,12 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, | |||
| 611 | if (!uobj) | 611 | if (!uobj) |
| 612 | return -ENOMEM; | 612 | return -ENOMEM; |
| 613 | 613 | ||
| 614 | uobj->user_handle = cmd.user_handle; | 614 | uobj->uobject.user_handle = cmd.user_handle; |
| 615 | uobj->context = file->ucontext; | 615 | uobj->uobject.context = file->ucontext; |
| 616 | uobj->comp_events_reported = 0; | ||
| 617 | uobj->async_events_reported = 0; | ||
| 618 | INIT_LIST_HEAD(&uobj->comp_list); | ||
| 619 | INIT_LIST_HEAD(&uobj->async_list); | ||
| 616 | 620 | ||
| 617 | cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe, | 621 | cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe, |
| 618 | file->ucontext, &udata); | 622 | file->ucontext, &udata); |
| @@ -622,7 +626,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, | |||
| 622 | } | 626 | } |
| 623 | 627 | ||
| 624 | cq->device = file->device->ib_dev; | 628 | cq->device = file->device->ib_dev; |
| 625 | cq->uobject = uobj; | 629 | cq->uobject = &uobj->uobject; |
| 626 | cq->comp_handler = ib_uverbs_comp_handler; | 630 | cq->comp_handler = ib_uverbs_comp_handler; |
| 627 | cq->event_handler = ib_uverbs_cq_event_handler; | 631 | cq->event_handler = ib_uverbs_cq_event_handler; |
| 628 | cq->cq_context = file; | 632 | cq->cq_context = file; |
| @@ -635,7 +639,7 @@ retry: | |||
| 635 | } | 639 | } |
| 636 | 640 | ||
| 637 | down(&ib_uverbs_idr_mutex); | 641 | down(&ib_uverbs_idr_mutex); |
| 638 | ret = idr_get_new(&ib_uverbs_cq_idr, cq, &uobj->id); | 642 | ret = idr_get_new(&ib_uverbs_cq_idr, cq, &uobj->uobject.id); |
| 639 | up(&ib_uverbs_idr_mutex); | 643 | up(&ib_uverbs_idr_mutex); |
| 640 | 644 | ||
| 641 | if (ret == -EAGAIN) | 645 | if (ret == -EAGAIN) |
| @@ -644,11 +648,11 @@ retry: | |||
| 644 | goto err_cq; | 648 | goto err_cq; |
| 645 | 649 | ||
| 646 | spin_lock_irq(&file->ucontext->lock); | 650 | spin_lock_irq(&file->ucontext->lock); |
| 647 | list_add_tail(&uobj->list, &file->ucontext->cq_list); | 651 | list_add_tail(&uobj->uobject.list, &file->ucontext->cq_list); |
| 648 | spin_unlock_irq(&file->ucontext->lock); | 652 | spin_unlock_irq(&file->ucontext->lock); |
| 649 | 653 | ||
| 650 | memset(&resp, 0, sizeof resp); | 654 | memset(&resp, 0, sizeof resp); |
| 651 | resp.cq_handle = uobj->id; | 655 | resp.cq_handle = uobj->uobject.id; |
| 652 | resp.cqe = cq->cqe; | 656 | resp.cqe = cq->cqe; |
| 653 | 657 | ||
| 654 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 658 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
| @@ -661,11 +665,11 @@ retry: | |||
| 661 | 665 | ||
| 662 | err_list: | 666 | err_list: |
| 663 | spin_lock_irq(&file->ucontext->lock); | 667 | spin_lock_irq(&file->ucontext->lock); |
| 664 | list_del(&uobj->list); | 668 | list_del(&uobj->uobject.list); |
| 665 | spin_unlock_irq(&file->ucontext->lock); | 669 | spin_unlock_irq(&file->ucontext->lock); |
| 666 | 670 | ||
| 667 | down(&ib_uverbs_idr_mutex); | 671 | down(&ib_uverbs_idr_mutex); |
| 668 | idr_remove(&ib_uverbs_cq_idr, uobj->id); | 672 | idr_remove(&ib_uverbs_cq_idr, uobj->uobject.id); |
| 669 | up(&ib_uverbs_idr_mutex); | 673 | up(&ib_uverbs_idr_mutex); |
| 670 | 674 | ||
| 671 | err_cq: | 675 | err_cq: |
| @@ -680,21 +684,27 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, | |||
| 680 | const char __user *buf, int in_len, | 684 | const char __user *buf, int in_len, |
| 681 | int out_len) | 685 | int out_len) |
| 682 | { | 686 | { |
| 683 | struct ib_uverbs_destroy_cq cmd; | 687 | struct ib_uverbs_destroy_cq cmd; |
| 684 | struct ib_cq *cq; | 688 | struct ib_uverbs_destroy_cq_resp resp; |
| 685 | struct ib_uobject *uobj; | 689 | struct ib_cq *cq; |
| 686 | int ret = -EINVAL; | 690 | struct ib_ucq_object *uobj; |
| 691 | struct ib_uverbs_event *evt, *tmp; | ||
| 692 | u64 user_handle; | ||
| 693 | int ret = -EINVAL; | ||
| 687 | 694 | ||
| 688 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 695 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
| 689 | return -EFAULT; | 696 | return -EFAULT; |
| 690 | 697 | ||
| 698 | memset(&resp, 0, sizeof resp); | ||
| 699 | |||
| 691 | down(&ib_uverbs_idr_mutex); | 700 | down(&ib_uverbs_idr_mutex); |
| 692 | 701 | ||
| 693 | cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); | 702 | cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle); |
| 694 | if (!cq || cq->uobject->context != file->ucontext) | 703 | if (!cq || cq->uobject->context != file->ucontext) |
| 695 | goto out; | 704 | goto out; |
| 696 | 705 | ||
| 697 | uobj = cq->uobject; | 706 | user_handle = cq->uobject->user_handle; |
| 707 | uobj = container_of(cq->uobject, struct ib_ucq_object, uobject); | ||
| 698 | 708 | ||
| 699 | ret = ib_destroy_cq(cq); | 709 | ret = ib_destroy_cq(cq); |
| 700 | if (ret) | 710 | if (ret) |
| @@ -703,11 +713,32 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, | |||
| 703 | idr_remove(&ib_uverbs_cq_idr, cmd.cq_handle); | 713 | idr_remove(&ib_uverbs_cq_idr, cmd.cq_handle); |
| 704 | 714 | ||
| 705 | spin_lock_irq(&file->ucontext->lock); | 715 | spin_lock_irq(&file->ucontext->lock); |
| 706 | list_del(&uobj->list); | 716 | list_del(&uobj->uobject.list); |
| 707 | spin_unlock_irq(&file->ucontext->lock); | 717 | spin_unlock_irq(&file->ucontext->lock); |
| 708 | 718 | ||
| 719 | spin_lock_irq(&file->comp_file[0].lock); | ||
| 720 | list_for_each_entry_safe(evt, tmp, &uobj->comp_list, obj_list) { | ||
| 721 | list_del(&evt->list); | ||
| 722 | kfree(evt); | ||
| 723 | } | ||
| 724 | spin_unlock_irq(&file->comp_file[0].lock); | ||
| 725 | |||
| 726 | spin_lock_irq(&file->async_file.lock); | ||
| 727 | list_for_each_entry_safe(evt, tmp, &uobj->async_list, obj_list) { | ||
| 728 | list_del(&evt->list); | ||
| 729 | kfree(evt); | ||
| 730 | } | ||
| 731 | spin_unlock_irq(&file->async_file.lock); | ||
| 732 | |||
| 733 | resp.comp_events_reported = uobj->comp_events_reported; | ||
| 734 | resp.async_events_reported = uobj->async_events_reported; | ||
| 735 | |||
| 709 | kfree(uobj); | 736 | kfree(uobj); |
| 710 | 737 | ||
| 738 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | ||
| 739 | &resp, sizeof resp)) | ||
| 740 | ret = -EFAULT; | ||
| 741 | |||
| 711 | out: | 742 | out: |
| 712 | up(&ib_uverbs_idr_mutex); | 743 | up(&ib_uverbs_idr_mutex); |
| 713 | 744 | ||
| @@ -721,7 +752,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, | |||
| 721 | struct ib_uverbs_create_qp cmd; | 752 | struct ib_uverbs_create_qp cmd; |
| 722 | struct ib_uverbs_create_qp_resp resp; | 753 | struct ib_uverbs_create_qp_resp resp; |
| 723 | struct ib_udata udata; | 754 | struct ib_udata udata; |
| 724 | struct ib_uobject *uobj; | 755 | struct ib_uevent_object *uobj; |
| 725 | struct ib_pd *pd; | 756 | struct ib_pd *pd; |
| 726 | struct ib_cq *scq, *rcq; | 757 | struct ib_cq *scq, *rcq; |
| 727 | struct ib_srq *srq; | 758 | struct ib_srq *srq; |
| @@ -772,8 +803,10 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, | |||
| 772 | attr.cap.max_recv_sge = cmd.max_recv_sge; | 803 | attr.cap.max_recv_sge = cmd.max_recv_sge; |
| 773 | attr.cap.max_inline_data = cmd.max_inline_data; | 804 | attr.cap.max_inline_data = cmd.max_inline_data; |
| 774 | 805 | ||
| 775 | uobj->user_handle = cmd.user_handle; | 806 | uobj->uobject.user_handle = cmd.user_handle; |
| 776 | uobj->context = file->ucontext; | 807 | uobj->uobject.context = file->ucontext; |
| 808 | uobj->events_reported = 0; | ||
| 809 | INIT_LIST_HEAD(&uobj->event_list); | ||
| 777 | 810 | ||
| 778 | qp = pd->device->create_qp(pd, &attr, &udata); | 811 | qp = pd->device->create_qp(pd, &attr, &udata); |
| 779 | if (IS_ERR(qp)) { | 812 | if (IS_ERR(qp)) { |
| @@ -786,7 +819,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, | |||
| 786 | qp->send_cq = attr.send_cq; | 819 | qp->send_cq = attr.send_cq; |
| 787 | qp->recv_cq = attr.recv_cq; | 820 | qp->recv_cq = attr.recv_cq; |
| 788 | qp->srq = attr.srq; | 821 | qp->srq = attr.srq; |
| 789 | qp->uobject = uobj; | 822 | qp->uobject = &uobj->uobject; |
| 790 | qp->event_handler = attr.event_handler; | 823 | qp->event_handler = attr.event_handler; |
| 791 | qp->qp_context = attr.qp_context; | 824 | qp->qp_context = attr.qp_context; |
| 792 | qp->qp_type = attr.qp_type; | 825 | qp->qp_type = attr.qp_type; |
| @@ -805,17 +838,17 @@ retry: | |||
| 805 | goto err_destroy; | 838 | goto err_destroy; |
| 806 | } | 839 | } |
| 807 | 840 | ||
| 808 | ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->id); | 841 | ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->uobject.id); |
| 809 | 842 | ||
| 810 | if (ret == -EAGAIN) | 843 | if (ret == -EAGAIN) |
| 811 | goto retry; | 844 | goto retry; |
| 812 | if (ret) | 845 | if (ret) |
| 813 | goto err_destroy; | 846 | goto err_destroy; |
| 814 | 847 | ||
| 815 | resp.qp_handle = uobj->id; | 848 | resp.qp_handle = uobj->uobject.id; |
| 816 | 849 | ||
| 817 | spin_lock_irq(&file->ucontext->lock); | 850 | spin_lock_irq(&file->ucontext->lock); |
| 818 | list_add_tail(&uobj->list, &file->ucontext->qp_list); | 851 | list_add_tail(&uobj->uobject.list, &file->ucontext->qp_list); |
| 819 | spin_unlock_irq(&file->ucontext->lock); | 852 | spin_unlock_irq(&file->ucontext->lock); |
| 820 | 853 | ||
| 821 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 854 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
| @@ -830,7 +863,7 @@ retry: | |||
| 830 | 863 | ||
| 831 | err_list: | 864 | err_list: |
| 832 | spin_lock_irq(&file->ucontext->lock); | 865 | spin_lock_irq(&file->ucontext->lock); |
| 833 | list_del(&uobj->list); | 866 | list_del(&uobj->uobject.list); |
| 834 | spin_unlock_irq(&file->ucontext->lock); | 867 | spin_unlock_irq(&file->ucontext->lock); |
| 835 | 868 | ||
| 836 | err_destroy: | 869 | err_destroy: |
| @@ -930,21 +963,25 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, | |||
| 930 | const char __user *buf, int in_len, | 963 | const char __user *buf, int in_len, |
| 931 | int out_len) | 964 | int out_len) |
| 932 | { | 965 | { |
| 933 | struct ib_uverbs_destroy_qp cmd; | 966 | struct ib_uverbs_destroy_qp cmd; |
| 934 | struct ib_qp *qp; | 967 | struct ib_uverbs_destroy_qp_resp resp; |
| 935 | struct ib_uobject *uobj; | 968 | struct ib_qp *qp; |
| 936 | int ret = -EINVAL; | 969 | struct ib_uevent_object *uobj; |
| 970 | struct ib_uverbs_event *evt, *tmp; | ||
| 971 | int ret = -EINVAL; | ||
| 937 | 972 | ||
| 938 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 973 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
| 939 | return -EFAULT; | 974 | return -EFAULT; |
| 940 | 975 | ||
| 976 | memset(&resp, 0, sizeof resp); | ||
| 977 | |||
| 941 | down(&ib_uverbs_idr_mutex); | 978 | down(&ib_uverbs_idr_mutex); |
| 942 | 979 | ||
| 943 | qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); | 980 | qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); |
| 944 | if (!qp || qp->uobject->context != file->ucontext) | 981 | if (!qp || qp->uobject->context != file->ucontext) |
| 945 | goto out; | 982 | goto out; |
| 946 | 983 | ||
| 947 | uobj = qp->uobject; | 984 | uobj = container_of(qp->uobject, struct ib_uevent_object, uobject); |
| 948 | 985 | ||
| 949 | ret = ib_destroy_qp(qp); | 986 | ret = ib_destroy_qp(qp); |
| 950 | if (ret) | 987 | if (ret) |
| @@ -953,11 +990,24 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, | |||
| 953 | idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle); | 990 | idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle); |
| 954 | 991 | ||
| 955 | spin_lock_irq(&file->ucontext->lock); | 992 | spin_lock_irq(&file->ucontext->lock); |
| 956 | list_del(&uobj->list); | 993 | list_del(&uobj->uobject.list); |
| 957 | spin_unlock_irq(&file->ucontext->lock); | 994 | spin_unlock_irq(&file->ucontext->lock); |
| 958 | 995 | ||
| 996 | spin_lock_irq(&file->async_file.lock); | ||
| 997 | list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { | ||
| 998 | list_del(&evt->list); | ||
| 999 | kfree(evt); | ||
| 1000 | } | ||
| 1001 | spin_unlock_irq(&file->async_file.lock); | ||
| 1002 | |||
| 1003 | resp.events_reported = uobj->events_reported; | ||
| 1004 | |||
| 959 | kfree(uobj); | 1005 | kfree(uobj); |
| 960 | 1006 | ||
| 1007 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | ||
| 1008 | &resp, sizeof resp)) | ||
| 1009 | ret = -EFAULT; | ||
| 1010 | |||
| 961 | out: | 1011 | out: |
| 962 | up(&ib_uverbs_idr_mutex); | 1012 | up(&ib_uverbs_idr_mutex); |
| 963 | 1013 | ||
| @@ -1015,7 +1065,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, | |||
| 1015 | struct ib_uverbs_create_srq cmd; | 1065 | struct ib_uverbs_create_srq cmd; |
| 1016 | struct ib_uverbs_create_srq_resp resp; | 1066 | struct ib_uverbs_create_srq_resp resp; |
| 1017 | struct ib_udata udata; | 1067 | struct ib_udata udata; |
| 1018 | struct ib_uobject *uobj; | 1068 | struct ib_uevent_object *uobj; |
| 1019 | struct ib_pd *pd; | 1069 | struct ib_pd *pd; |
| 1020 | struct ib_srq *srq; | 1070 | struct ib_srq *srq; |
| 1021 | struct ib_srq_init_attr attr; | 1071 | struct ib_srq_init_attr attr; |
| @@ -1050,8 +1100,10 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, | |||
| 1050 | attr.attr.max_sge = cmd.max_sge; | 1100 | attr.attr.max_sge = cmd.max_sge; |
| 1051 | attr.attr.srq_limit = cmd.srq_limit; | 1101 | attr.attr.srq_limit = cmd.srq_limit; |
| 1052 | 1102 | ||
| 1053 | uobj->user_handle = cmd.user_handle; | 1103 | uobj->uobject.user_handle = cmd.user_handle; |
| 1054 | uobj->context = file->ucontext; | 1104 | uobj->uobject.context = file->ucontext; |
| 1105 | uobj->events_reported = 0; | ||
| 1106 | INIT_LIST_HEAD(&uobj->event_list); | ||
| 1055 | 1107 | ||
| 1056 | srq = pd->device->create_srq(pd, &attr, &udata); | 1108 | srq = pd->device->create_srq(pd, &attr, &udata); |
| 1057 | if (IS_ERR(srq)) { | 1109 | if (IS_ERR(srq)) { |
| @@ -1061,7 +1113,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, | |||
| 1061 | 1113 | ||
| 1062 | srq->device = pd->device; | 1114 | srq->device = pd->device; |
| 1063 | srq->pd = pd; | 1115 | srq->pd = pd; |
| 1064 | srq->uobject = uobj; | 1116 | srq->uobject = &uobj->uobject; |
| 1065 | srq->event_handler = attr.event_handler; | 1117 | srq->event_handler = attr.event_handler; |
| 1066 | srq->srq_context = attr.srq_context; | 1118 | srq->srq_context = attr.srq_context; |
| 1067 | atomic_inc(&pd->usecnt); | 1119 | atomic_inc(&pd->usecnt); |
| @@ -1075,17 +1127,17 @@ retry: | |||
| 1075 | goto err_destroy; | 1127 | goto err_destroy; |
| 1076 | } | 1128 | } |
| 1077 | 1129 | ||
| 1078 | ret = idr_get_new(&ib_uverbs_srq_idr, srq, &uobj->id); | 1130 | ret = idr_get_new(&ib_uverbs_srq_idr, srq, &uobj->uobject.id); |
| 1079 | 1131 | ||
| 1080 | if (ret == -EAGAIN) | 1132 | if (ret == -EAGAIN) |
| 1081 | goto retry; | 1133 | goto retry; |
| 1082 | if (ret) | 1134 | if (ret) |
| 1083 | goto err_destroy; | 1135 | goto err_destroy; |
| 1084 | 1136 | ||
| 1085 | resp.srq_handle = uobj->id; | 1137 | resp.srq_handle = uobj->uobject.id; |
| 1086 | 1138 | ||
| 1087 | spin_lock_irq(&file->ucontext->lock); | 1139 | spin_lock_irq(&file->ucontext->lock); |
| 1088 | list_add_tail(&uobj->list, &file->ucontext->srq_list); | 1140 | list_add_tail(&uobj->uobject.list, &file->ucontext->srq_list); |
| 1089 | spin_unlock_irq(&file->ucontext->lock); | 1141 | spin_unlock_irq(&file->ucontext->lock); |
| 1090 | 1142 | ||
| 1091 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 1143 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
| @@ -1100,7 +1152,7 @@ retry: | |||
| 1100 | 1152 | ||
| 1101 | err_list: | 1153 | err_list: |
| 1102 | spin_lock_irq(&file->ucontext->lock); | 1154 | spin_lock_irq(&file->ucontext->lock); |
| 1103 | list_del(&uobj->list); | 1155 | list_del(&uobj->uobject.list); |
| 1104 | spin_unlock_irq(&file->ucontext->lock); | 1156 | spin_unlock_irq(&file->ucontext->lock); |
| 1105 | 1157 | ||
| 1106 | err_destroy: | 1158 | err_destroy: |
| @@ -1149,21 +1201,25 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, | |||
| 1149 | const char __user *buf, int in_len, | 1201 | const char __user *buf, int in_len, |
| 1150 | int out_len) | 1202 | int out_len) |
| 1151 | { | 1203 | { |
| 1152 | struct ib_uverbs_destroy_srq cmd; | 1204 | struct ib_uverbs_destroy_srq cmd; |
| 1153 | struct ib_srq *srq; | 1205 | struct ib_uverbs_destroy_srq_resp resp; |
| 1154 | struct ib_uobject *uobj; | 1206 | struct ib_srq *srq; |
| 1155 | int ret = -EINVAL; | 1207 | struct ib_uevent_object *uobj; |
| 1208 | struct ib_uverbs_event *evt, *tmp; | ||
| 1209 | int ret = -EINVAL; | ||
| 1156 | 1210 | ||
| 1157 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 1211 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
| 1158 | return -EFAULT; | 1212 | return -EFAULT; |
| 1159 | 1213 | ||
| 1160 | down(&ib_uverbs_idr_mutex); | 1214 | down(&ib_uverbs_idr_mutex); |
| 1161 | 1215 | ||
| 1216 | memset(&resp, 0, sizeof resp); | ||
| 1217 | |||
| 1162 | srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle); | 1218 | srq = idr_find(&ib_uverbs_srq_idr, cmd.srq_handle); |
| 1163 | if (!srq || srq->uobject->context != file->ucontext) | 1219 | if (!srq || srq->uobject->context != file->ucontext) |
| 1164 | goto out; | 1220 | goto out; |
| 1165 | 1221 | ||
| 1166 | uobj = srq->uobject; | 1222 | uobj = container_of(srq->uobject, struct ib_uevent_object, uobject); |
| 1167 | 1223 | ||
| 1168 | ret = ib_destroy_srq(srq); | 1224 | ret = ib_destroy_srq(srq); |
| 1169 | if (ret) | 1225 | if (ret) |
| @@ -1172,11 +1228,24 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, | |||
| 1172 | idr_remove(&ib_uverbs_srq_idr, cmd.srq_handle); | 1228 | idr_remove(&ib_uverbs_srq_idr, cmd.srq_handle); |
| 1173 | 1229 | ||
| 1174 | spin_lock_irq(&file->ucontext->lock); | 1230 | spin_lock_irq(&file->ucontext->lock); |
| 1175 | list_del(&uobj->list); | 1231 | list_del(&uobj->uobject.list); |
| 1176 | spin_unlock_irq(&file->ucontext->lock); | 1232 | spin_unlock_irq(&file->ucontext->lock); |
| 1177 | 1233 | ||
| 1234 | spin_lock_irq(&file->async_file.lock); | ||
| 1235 | list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { | ||
| 1236 | list_del(&evt->list); | ||
| 1237 | kfree(evt); | ||
| 1238 | } | ||
| 1239 | spin_unlock_irq(&file->async_file.lock); | ||
| 1240 | |||
| 1241 | resp.events_reported = uobj->events_reported; | ||
| 1242 | |||
| 1178 | kfree(uobj); | 1243 | kfree(uobj); |
| 1179 | 1244 | ||
| 1245 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | ||
| 1246 | &resp, sizeof resp)) | ||
| 1247 | ret = -EFAULT; | ||
| 1248 | |||
| 1180 | out: | 1249 | out: |
| 1181 | up(&ib_uverbs_idr_mutex); | 1250 | up(&ib_uverbs_idr_mutex); |
| 1182 | 1251 | ||
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 09caf5b1ef36..ce5bdb7af306 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c | |||
| @@ -120,7 +120,7 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context) | |||
| 120 | idr_remove(&ib_uverbs_qp_idr, uobj->id); | 120 | idr_remove(&ib_uverbs_qp_idr, uobj->id); |
| 121 | ib_destroy_qp(qp); | 121 | ib_destroy_qp(qp); |
| 122 | list_del(&uobj->list); | 122 | list_del(&uobj->list); |
| 123 | kfree(uobj); | 123 | kfree(container_of(uobj, struct ib_uevent_object, uobject)); |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) { | 126 | list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) { |
| @@ -128,7 +128,7 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context) | |||
| 128 | idr_remove(&ib_uverbs_cq_idr, uobj->id); | 128 | idr_remove(&ib_uverbs_cq_idr, uobj->id); |
| 129 | ib_destroy_cq(cq); | 129 | ib_destroy_cq(cq); |
| 130 | list_del(&uobj->list); | 130 | list_del(&uobj->list); |
| 131 | kfree(uobj); | 131 | kfree(container_of(uobj, struct ib_ucq_object, uobject)); |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) { | 134 | list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) { |
| @@ -136,7 +136,7 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context) | |||
| 136 | idr_remove(&ib_uverbs_srq_idr, uobj->id); | 136 | idr_remove(&ib_uverbs_srq_idr, uobj->id); |
| 137 | ib_destroy_srq(srq); | 137 | ib_destroy_srq(srq); |
| 138 | list_del(&uobj->list); | 138 | list_del(&uobj->list); |
| 139 | kfree(uobj); | 139 | kfree(container_of(uobj, struct ib_uevent_object, uobject)); |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | /* XXX Free MWs */ | 142 | /* XXX Free MWs */ |
| @@ -182,7 +182,7 @@ static ssize_t ib_uverbs_event_read(struct file *filp, char __user *buf, | |||
| 182 | size_t count, loff_t *pos) | 182 | size_t count, loff_t *pos) |
| 183 | { | 183 | { |
| 184 | struct ib_uverbs_event_file *file = filp->private_data; | 184 | struct ib_uverbs_event_file *file = filp->private_data; |
| 185 | void *event; | 185 | struct ib_uverbs_event *event; |
| 186 | int eventsz; | 186 | int eventsz; |
| 187 | int ret = 0; | 187 | int ret = 0; |
| 188 | 188 | ||
| @@ -207,21 +207,23 @@ static ssize_t ib_uverbs_event_read(struct file *filp, char __user *buf, | |||
| 207 | return -ENODEV; | 207 | return -ENODEV; |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | if (file->is_async) { | 210 | event = list_entry(file->event_list.next, struct ib_uverbs_event, list); |
| 211 | event = list_entry(file->event_list.next, | 211 | |
| 212 | struct ib_uverbs_async_event, list); | 212 | if (file->is_async) |
| 213 | eventsz = sizeof (struct ib_uverbs_async_event_desc); | 213 | eventsz = sizeof (struct ib_uverbs_async_event_desc); |
| 214 | } else { | 214 | else |
| 215 | event = list_entry(file->event_list.next, | ||
| 216 | struct ib_uverbs_comp_event, list); | ||
| 217 | eventsz = sizeof (struct ib_uverbs_comp_event_desc); | 215 | eventsz = sizeof (struct ib_uverbs_comp_event_desc); |
| 218 | } | ||
| 219 | 216 | ||
| 220 | if (eventsz > count) { | 217 | if (eventsz > count) { |
| 221 | ret = -EINVAL; | 218 | ret = -EINVAL; |
| 222 | event = NULL; | 219 | event = NULL; |
| 223 | } else | 220 | } else { |
| 224 | list_del(file->event_list.next); | 221 | list_del(file->event_list.next); |
| 222 | if (event->counter) { | ||
| 223 | ++(*event->counter); | ||
| 224 | list_del(&event->obj_list); | ||
| 225 | } | ||
| 226 | } | ||
| 225 | 227 | ||
| 226 | spin_unlock_irq(&file->lock); | 228 | spin_unlock_irq(&file->lock); |
| 227 | 229 | ||
| @@ -257,16 +259,13 @@ static unsigned int ib_uverbs_event_poll(struct file *filp, | |||
| 257 | 259 | ||
| 258 | static void ib_uverbs_event_release(struct ib_uverbs_event_file *file) | 260 | static void ib_uverbs_event_release(struct ib_uverbs_event_file *file) |
| 259 | { | 261 | { |
| 260 | struct list_head *entry, *tmp; | 262 | struct ib_uverbs_event *entry, *tmp; |
| 261 | 263 | ||
| 262 | spin_lock_irq(&file->lock); | 264 | spin_lock_irq(&file->lock); |
| 263 | if (file->fd != -1) { | 265 | if (file->fd != -1) { |
| 264 | file->fd = -1; | 266 | file->fd = -1; |
| 265 | list_for_each_safe(entry, tmp, &file->event_list) | 267 | list_for_each_entry_safe(entry, tmp, &file->event_list, list) |
| 266 | if (file->is_async) | 268 | kfree(entry); |
| 267 | kfree(list_entry(entry, struct ib_uverbs_async_event, list)); | ||
| 268 | else | ||
| 269 | kfree(list_entry(entry, struct ib_uverbs_comp_event, list)); | ||
| 270 | } | 269 | } |
| 271 | spin_unlock_irq(&file->lock); | 270 | spin_unlock_irq(&file->lock); |
| 272 | } | 271 | } |
| @@ -304,18 +303,23 @@ static struct file_operations uverbs_event_fops = { | |||
| 304 | 303 | ||
| 305 | void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context) | 304 | void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context) |
| 306 | { | 305 | { |
| 307 | struct ib_uverbs_file *file = cq_context; | 306 | struct ib_uverbs_file *file = cq_context; |
| 308 | struct ib_uverbs_comp_event *entry; | 307 | struct ib_ucq_object *uobj; |
| 309 | unsigned long flags; | 308 | struct ib_uverbs_event *entry; |
| 309 | unsigned long flags; | ||
| 310 | 310 | ||
| 311 | entry = kmalloc(sizeof *entry, GFP_ATOMIC); | 311 | entry = kmalloc(sizeof *entry, GFP_ATOMIC); |
| 312 | if (!entry) | 312 | if (!entry) |
| 313 | return; | 313 | return; |
| 314 | 314 | ||
| 315 | entry->desc.cq_handle = cq->uobject->user_handle; | 315 | uobj = container_of(cq->uobject, struct ib_ucq_object, uobject); |
| 316 | |||
| 317 | entry->desc.comp.cq_handle = cq->uobject->user_handle; | ||
| 318 | entry->counter = &uobj->comp_events_reported; | ||
| 316 | 319 | ||
| 317 | spin_lock_irqsave(&file->comp_file[0].lock, flags); | 320 | spin_lock_irqsave(&file->comp_file[0].lock, flags); |
| 318 | list_add_tail(&entry->list, &file->comp_file[0].event_list); | 321 | list_add_tail(&entry->list, &file->comp_file[0].event_list); |
| 322 | list_add_tail(&entry->obj_list, &uobj->comp_list); | ||
| 319 | spin_unlock_irqrestore(&file->comp_file[0].lock, flags); | 323 | spin_unlock_irqrestore(&file->comp_file[0].lock, flags); |
| 320 | 324 | ||
| 321 | wake_up_interruptible(&file->comp_file[0].poll_wait); | 325 | wake_up_interruptible(&file->comp_file[0].poll_wait); |
| @@ -323,20 +327,25 @@ void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context) | |||
| 323 | } | 327 | } |
| 324 | 328 | ||
| 325 | static void ib_uverbs_async_handler(struct ib_uverbs_file *file, | 329 | static void ib_uverbs_async_handler(struct ib_uverbs_file *file, |
| 326 | __u64 element, __u64 event) | 330 | __u64 element, __u64 event, |
| 331 | struct list_head *obj_list, | ||
| 332 | u32 *counter) | ||
| 327 | { | 333 | { |
| 328 | struct ib_uverbs_async_event *entry; | 334 | struct ib_uverbs_event *entry; |
| 329 | unsigned long flags; | 335 | unsigned long flags; |
| 330 | 336 | ||
| 331 | entry = kmalloc(sizeof *entry, GFP_ATOMIC); | 337 | entry = kmalloc(sizeof *entry, GFP_ATOMIC); |
| 332 | if (!entry) | 338 | if (!entry) |
| 333 | return; | 339 | return; |
| 334 | 340 | ||
| 335 | entry->desc.element = element; | 341 | entry->desc.async.element = element; |
| 336 | entry->desc.event_type = event; | 342 | entry->desc.async.event_type = event; |
| 343 | entry->counter = counter; | ||
| 337 | 344 | ||
| 338 | spin_lock_irqsave(&file->async_file.lock, flags); | 345 | spin_lock_irqsave(&file->async_file.lock, flags); |
| 339 | list_add_tail(&entry->list, &file->async_file.event_list); | 346 | list_add_tail(&entry->list, &file->async_file.event_list); |
| 347 | if (obj_list) | ||
| 348 | list_add_tail(&entry->obj_list, obj_list); | ||
| 340 | spin_unlock_irqrestore(&file->async_file.lock, flags); | 349 | spin_unlock_irqrestore(&file->async_file.lock, flags); |
| 341 | 350 | ||
| 342 | wake_up_interruptible(&file->async_file.poll_wait); | 351 | wake_up_interruptible(&file->async_file.poll_wait); |
| @@ -345,23 +354,39 @@ static void ib_uverbs_async_handler(struct ib_uverbs_file *file, | |||
| 345 | 354 | ||
| 346 | void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr) | 355 | void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr) |
| 347 | { | 356 | { |
| 348 | ib_uverbs_async_handler(context_ptr, | 357 | struct ib_ucq_object *uobj; |
| 349 | event->element.cq->uobject->user_handle, | 358 | |
| 350 | event->event); | 359 | uobj = container_of(event->element.cq->uobject, |
| 360 | struct ib_ucq_object, uobject); | ||
| 361 | |||
| 362 | ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle, | ||
| 363 | event->event, &uobj->async_list, | ||
| 364 | &uobj->async_events_reported); | ||
| 365 | |||
| 351 | } | 366 | } |
| 352 | 367 | ||
| 353 | void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr) | 368 | void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr) |
| 354 | { | 369 | { |
| 355 | ib_uverbs_async_handler(context_ptr, | 370 | struct ib_uevent_object *uobj; |
| 356 | event->element.qp->uobject->user_handle, | 371 | |
| 357 | event->event); | 372 | uobj = container_of(event->element.qp->uobject, |
| 373 | struct ib_uevent_object, uobject); | ||
| 374 | |||
| 375 | ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle, | ||
| 376 | event->event, &uobj->event_list, | ||
| 377 | &uobj->events_reported); | ||
| 358 | } | 378 | } |
| 359 | 379 | ||
| 360 | void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr) | 380 | void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr) |
| 361 | { | 381 | { |
| 362 | ib_uverbs_async_handler(context_ptr, | 382 | struct ib_uevent_object *uobj; |
| 363 | event->element.srq->uobject->user_handle, | 383 | |
| 364 | event->event); | 384 | uobj = container_of(event->element.srq->uobject, |
| 385 | struct ib_uevent_object, uobject); | ||
| 386 | |||
| 387 | ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle, | ||
| 388 | event->event, &uobj->event_list, | ||
| 389 | &uobj->events_reported); | ||
| 365 | } | 390 | } |
| 366 | 391 | ||
| 367 | static void ib_uverbs_event_handler(struct ib_event_handler *handler, | 392 | static void ib_uverbs_event_handler(struct ib_event_handler *handler, |
| @@ -370,7 +395,8 @@ static void ib_uverbs_event_handler(struct ib_event_handler *handler, | |||
| 370 | struct ib_uverbs_file *file = | 395 | struct ib_uverbs_file *file = |
| 371 | container_of(handler, struct ib_uverbs_file, event_handler); | 396 | container_of(handler, struct ib_uverbs_file, event_handler); |
| 372 | 397 | ||
| 373 | ib_uverbs_async_handler(file, event->element.port_num, event->event); | 398 | ib_uverbs_async_handler(file, event->element.port_num, event->event, |
| 399 | NULL, NULL); | ||
| 374 | } | 400 | } |
| 375 | 401 | ||
| 376 | static int ib_uverbs_event_init(struct ib_uverbs_event_file *file, | 402 | static int ib_uverbs_event_init(struct ib_uverbs_event_file *file, |
diff --git a/include/rdma/ib_user_verbs.h b/include/rdma/ib_user_verbs.h index 7ebb01c8f996..fd85725391a4 100644 --- a/include/rdma/ib_user_verbs.h +++ b/include/rdma/ib_user_verbs.h | |||
| @@ -42,7 +42,7 @@ | |||
| 42 | * Increment this value if any changes that break userspace ABI | 42 | * Increment this value if any changes that break userspace ABI |
| 43 | * compatibility are made. | 43 | * compatibility are made. |
| 44 | */ | 44 | */ |
| 45 | #define IB_USER_VERBS_ABI_VERSION 1 | 45 | #define IB_USER_VERBS_ABI_VERSION 2 |
| 46 | 46 | ||
| 47 | enum { | 47 | enum { |
| 48 | IB_USER_VERBS_CMD_QUERY_PARAMS, | 48 | IB_USER_VERBS_CMD_QUERY_PARAMS, |
| @@ -292,7 +292,14 @@ struct ib_uverbs_create_cq_resp { | |||
| 292 | }; | 292 | }; |
| 293 | 293 | ||
| 294 | struct ib_uverbs_destroy_cq { | 294 | struct ib_uverbs_destroy_cq { |
| 295 | __u64 response; | ||
| 295 | __u32 cq_handle; | 296 | __u32 cq_handle; |
| 297 | __u32 reserved; | ||
| 298 | }; | ||
| 299 | |||
| 300 | struct ib_uverbs_destroy_cq_resp { | ||
| 301 | __u32 comp_events_reported; | ||
| 302 | __u32 async_events_reported; | ||
| 296 | }; | 303 | }; |
| 297 | 304 | ||
| 298 | struct ib_uverbs_create_qp { | 305 | struct ib_uverbs_create_qp { |
| @@ -372,7 +379,13 @@ struct ib_uverbs_modify_qp_resp { | |||
| 372 | }; | 379 | }; |
| 373 | 380 | ||
| 374 | struct ib_uverbs_destroy_qp { | 381 | struct ib_uverbs_destroy_qp { |
| 382 | __u64 response; | ||
| 375 | __u32 qp_handle; | 383 | __u32 qp_handle; |
| 384 | __u32 reserved; | ||
| 385 | }; | ||
| 386 | |||
| 387 | struct ib_uverbs_destroy_qp_resp { | ||
| 388 | __u32 events_reported; | ||
| 376 | }; | 389 | }; |
| 377 | 390 | ||
| 378 | struct ib_uverbs_attach_mcast { | 391 | struct ib_uverbs_attach_mcast { |
| @@ -416,7 +429,13 @@ struct ib_uverbs_modify_srq { | |||
| 416 | }; | 429 | }; |
| 417 | 430 | ||
| 418 | struct ib_uverbs_destroy_srq { | 431 | struct ib_uverbs_destroy_srq { |
| 432 | __u64 response; | ||
| 419 | __u32 srq_handle; | 433 | __u32 srq_handle; |
| 434 | __u32 reserved; | ||
| 435 | }; | ||
| 436 | |||
| 437 | struct ib_uverbs_destroy_srq_resp { | ||
| 438 | __u32 events_reported; | ||
| 420 | }; | 439 | }; |
| 421 | 440 | ||
| 422 | #endif /* IB_USER_VERBS_H */ | 441 | #endif /* IB_USER_VERBS_H */ |
