IB/uverbs: track multicast group membership for userspace QPs

uverbs needs to track which multicast groups is each qp
attached to, in order to properly detach when cleanup
is performed on device file close.

Signed-off-by: Jack Morgenstein <jackm@mellanox.co.il>
Signed-off-by: Michael S. Tsirkin <mst@mellanox.co.il>
Signed-off-by: Roland Dreier <rolandd@cisco.com>

authored by Jack Morgenstein and committed by Roland Dreier f4e40156 e0ae9ecf

+99 -23
+11
drivers/infiniband/core/uverbs.h
··· 105 u32 *counter; 106 }; 107 108 struct ib_uevent_object { 109 struct ib_uobject uobject; 110 struct list_head event_list; 111 u32 events_reported; 112 }; 113 114 struct ib_ucq_object {
··· 105 u32 *counter; 106 }; 107 108 + struct ib_uverbs_mcast_entry { 109 + struct list_head list; 110 + union ib_gid gid; 111 + u16 lid; 112 + }; 113 + 114 struct ib_uevent_object { 115 struct ib_uobject uobject; 116 struct list_head event_list; 117 u32 events_reported; 118 + }; 119 + 120 + struct ib_uqp_object { 121 + struct ib_uevent_object uevent; 122 + struct list_head mcast_list; 123 }; 124 125 struct ib_ucq_object {
+71 -19
drivers/infiniband/core/uverbs_cmd.c
··· 815 struct ib_uverbs_create_qp cmd; 816 struct ib_uverbs_create_qp_resp resp; 817 struct ib_udata udata; 818 - struct ib_uevent_object *uobj; 819 struct ib_pd *pd; 820 struct ib_cq *scq, *rcq; 821 struct ib_srq *srq; ··· 866 attr.cap.max_recv_sge = cmd.max_recv_sge; 867 attr.cap.max_inline_data = cmd.max_inline_data; 868 869 - uobj->uobject.user_handle = cmd.user_handle; 870 - uobj->uobject.context = file->ucontext; 871 - uobj->events_reported = 0; 872 - INIT_LIST_HEAD(&uobj->event_list); 873 874 qp = pd->device->create_qp(pd, &attr, &udata); 875 if (IS_ERR(qp)) { ··· 883 qp->send_cq = attr.send_cq; 884 qp->recv_cq = attr.recv_cq; 885 qp->srq = attr.srq; 886 - qp->uobject = &uobj->uobject; 887 qp->event_handler = attr.event_handler; 888 qp->qp_context = attr.qp_context; 889 qp->qp_type = attr.qp_type; ··· 902 goto err_destroy; 903 } 904 905 - ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->uobject.id); 906 907 if (ret == -EAGAIN) 908 goto retry; 909 if (ret) 910 goto err_destroy; 911 912 - resp.qp_handle = uobj->uobject.id; 913 resp.max_recv_sge = attr.cap.max_recv_sge; 914 resp.max_send_sge = attr.cap.max_send_sge; 915 resp.max_recv_wr = attr.cap.max_recv_wr; ··· 923 } 924 925 down(&file->mutex); 926 - list_add_tail(&uobj->uobject.list, &file->ucontext->qp_list); 927 up(&file->mutex); 928 929 up(&ib_uverbs_idr_mutex); ··· 931 return in_len; 932 933 err_idr: 934 - idr_remove(&ib_uverbs_qp_idr, uobj->uobject.id); 935 936 err_destroy: 937 ib_destroy_qp(qp); ··· 1033 struct ib_uverbs_destroy_qp cmd; 1034 struct ib_uverbs_destroy_qp_resp resp; 1035 struct ib_qp *qp; 1036 - struct ib_uevent_object *uobj; 1037 int ret = -EINVAL; 1038 1039 if (copy_from_user(&cmd, buf, sizeof cmd)) ··· 1047 if (!qp || qp->uobject->context != file->ucontext) 1048 goto out; 1049 1050 - uobj = container_of(qp->uobject, struct ib_uevent_object, uobject); 1051 1052 ret = ib_destroy_qp(qp); 1053 if (ret) ··· 1061 idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle); 1062 1063 down(&file->mutex); 1064 - list_del(&uobj->uobject.list); 1065 up(&file->mutex); 1066 1067 - ib_uverbs_release_uevent(file, uobj); 1068 1069 - resp.events_reported = uobj->events_reported; 1070 1071 kfree(uobj); 1072 ··· 1548 { 1549 struct ib_uverbs_attach_mcast cmd; 1550 struct ib_qp *qp; 1551 int ret = -EINVAL; 1552 1553 if (copy_from_user(&cmd, buf, sizeof cmd)) ··· 1558 down(&ib_uverbs_idr_mutex); 1559 1560 qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); 1561 - if (qp && qp->uobject->context == file->ucontext) 1562 - ret = ib_attach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid); 1563 1564 up(&ib_uverbs_idr_mutex); 1565 1566 return ret ? ret : in_len; ··· 1598 int out_len) 1599 { 1600 struct ib_uverbs_detach_mcast cmd; 1601 struct ib_qp *qp; 1602 int ret = -EINVAL; 1603 1604 if (copy_from_user(&cmd, buf, sizeof cmd)) ··· 1609 down(&ib_uverbs_idr_mutex); 1610 1611 qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); 1612 - if (qp && qp->uobject->context == file->ucontext) 1613 - ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid); 1614 1615 up(&ib_uverbs_idr_mutex); 1616 1617 return ret ? ret : in_len;
··· 815 struct ib_uverbs_create_qp cmd; 816 struct ib_uverbs_create_qp_resp resp; 817 struct ib_udata udata; 818 + struct ib_uqp_object *uobj; 819 struct ib_pd *pd; 820 struct ib_cq *scq, *rcq; 821 struct ib_srq *srq; ··· 866 attr.cap.max_recv_sge = cmd.max_recv_sge; 867 attr.cap.max_inline_data = cmd.max_inline_data; 868 869 + uobj->uevent.uobject.user_handle = cmd.user_handle; 870 + uobj->uevent.uobject.context = file->ucontext; 871 + uobj->uevent.events_reported = 0; 872 + INIT_LIST_HEAD(&uobj->uevent.event_list); 873 + INIT_LIST_HEAD(&uobj->mcast_list); 874 875 qp = pd->device->create_qp(pd, &attr, &udata); 876 if (IS_ERR(qp)) { ··· 882 qp->send_cq = attr.send_cq; 883 qp->recv_cq = attr.recv_cq; 884 qp->srq = attr.srq; 885 + qp->uobject = &uobj->uevent.uobject; 886 qp->event_handler = attr.event_handler; 887 qp->qp_context = attr.qp_context; 888 qp->qp_type = attr.qp_type; ··· 901 goto err_destroy; 902 } 903 904 + ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->uevent.uobject.id); 905 906 if (ret == -EAGAIN) 907 goto retry; 908 if (ret) 909 goto err_destroy; 910 911 + resp.qp_handle = uobj->uevent.uobject.id; 912 resp.max_recv_sge = attr.cap.max_recv_sge; 913 resp.max_send_sge = attr.cap.max_send_sge; 914 resp.max_recv_wr = attr.cap.max_recv_wr; ··· 922 } 923 924 down(&file->mutex); 925 + list_add_tail(&uobj->uevent.uobject.list, &file->ucontext->qp_list); 926 up(&file->mutex); 927 928 up(&ib_uverbs_idr_mutex); ··· 930 return in_len; 931 932 err_idr: 933 + idr_remove(&ib_uverbs_qp_idr, uobj->uevent.uobject.id); 934 935 err_destroy: 936 ib_destroy_qp(qp); ··· 1032 struct ib_uverbs_destroy_qp cmd; 1033 struct ib_uverbs_destroy_qp_resp resp; 1034 struct ib_qp *qp; 1035 + struct ib_uqp_object *uobj; 1036 int ret = -EINVAL; 1037 1038 if (copy_from_user(&cmd, buf, sizeof cmd)) ··· 1046 if (!qp || qp->uobject->context != file->ucontext) 1047 goto out; 1048 1049 + uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); 1050 + 1051 + if (!list_empty(&uobj->mcast_list)) { 1052 + ret = -EBUSY; 1053 + goto out; 1054 + } 1055 1056 ret = ib_destroy_qp(qp); 1057 if (ret) ··· 1055 idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle); 1056 1057 down(&file->mutex); 1058 + list_del(&uobj->uevent.uobject.list); 1059 up(&file->mutex); 1060 1061 + ib_uverbs_release_uevent(file, &uobj->uevent); 1062 1063 + resp.events_reported = uobj->uevent.events_reported; 1064 1065 kfree(uobj); 1066 ··· 1542 { 1543 struct ib_uverbs_attach_mcast cmd; 1544 struct ib_qp *qp; 1545 + struct ib_uqp_object *uobj; 1546 + struct ib_uverbs_mcast_entry *mcast; 1547 int ret = -EINVAL; 1548 1549 if (copy_from_user(&cmd, buf, sizeof cmd)) ··· 1550 down(&ib_uverbs_idr_mutex); 1551 1552 qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); 1553 + if (!qp || qp->uobject->context != file->ucontext) 1554 + goto out; 1555 1556 + uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); 1557 + 1558 + list_for_each_entry(mcast, &uobj->mcast_list, list) 1559 + if (cmd.mlid == mcast->lid && 1560 + !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) { 1561 + ret = 0; 1562 + goto out; 1563 + } 1564 + 1565 + mcast = kmalloc(sizeof *mcast, GFP_KERNEL); 1566 + if (!mcast) { 1567 + ret = -ENOMEM; 1568 + goto out; 1569 + } 1570 + 1571 + mcast->lid = cmd.mlid; 1572 + memcpy(mcast->gid.raw, cmd.gid, sizeof mcast->gid.raw); 1573 + 1574 + ret = ib_attach_mcast(qp, &mcast->gid, cmd.mlid); 1575 + if (!ret) { 1576 + uobj = container_of(qp->uobject, struct ib_uqp_object, 1577 + uevent.uobject); 1578 + list_add_tail(&mcast->list, &uobj->mcast_list); 1579 + } else 1580 + kfree(mcast); 1581 + 1582 + out: 1583 up(&ib_uverbs_idr_mutex); 1584 1585 return ret ? ret : in_len; ··· 1563 int out_len) 1564 { 1565 struct ib_uverbs_detach_mcast cmd; 1566 + struct ib_uqp_object *uobj; 1567 struct ib_qp *qp; 1568 + struct ib_uverbs_mcast_entry *mcast; 1569 int ret = -EINVAL; 1570 1571 if (copy_from_user(&cmd, buf, sizeof cmd)) ··· 1572 down(&ib_uverbs_idr_mutex); 1573 1574 qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle); 1575 + if (!qp || qp->uobject->context != file->ucontext) 1576 + goto out; 1577 1578 + ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid); 1579 + if (ret) 1580 + goto out; 1581 + 1582 + uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject); 1583 + 1584 + list_for_each_entry(mcast, &uobj->mcast_list, list) 1585 + if (cmd.mlid == mcast->lid && 1586 + !memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) { 1587 + list_del(&mcast->list); 1588 + kfree(mcast); 1589 + break; 1590 + } 1591 + 1592 + out: 1593 up(&ib_uverbs_idr_mutex); 1594 1595 return ret ? ret : in_len;
+17 -4
drivers/infiniband/core/uverbs_main.c
··· 160 spin_unlock_irq(&file->async_file->lock); 161 } 162 163 static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, 164 struct ib_ucontext *context) 165 { ··· 192 193 list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { 194 struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id); 195 - struct ib_uevent_object *uevent = 196 - container_of(uobj, struct ib_uevent_object, uobject); 197 idr_remove(&ib_uverbs_qp_idr, uobj->id); 198 ib_destroy_qp(qp); 199 list_del(&uobj->list); 200 - ib_uverbs_release_uevent(file, uevent); 201 - kfree(uevent); 202 } 203 204 list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) {
··· 160 spin_unlock_irq(&file->async_file->lock); 161 } 162 163 + static void ib_uverbs_detach_umcast(struct ib_qp *qp, 164 + struct ib_uqp_object *uobj) 165 + { 166 + struct ib_uverbs_mcast_entry *mcast, *tmp; 167 + 168 + list_for_each_entry_safe(mcast, tmp, &uobj->mcast_list, list) { 169 + ib_detach_mcast(qp, &mcast->gid, mcast->lid); 170 + list_del(&mcast->list); 171 + kfree(mcast); 172 + } 173 + } 174 + 175 static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, 176 struct ib_ucontext *context) 177 { ··· 180 181 list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { 182 struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id); 183 + struct ib_uqp_object *uqp = 184 + container_of(uobj, struct ib_uqp_object, uevent.uobject); 185 idr_remove(&ib_uverbs_qp_idr, uobj->id); 186 + ib_uverbs_detach_umcast(qp, uqp); 187 ib_destroy_qp(qp); 188 list_del(&uobj->list); 189 + ib_uverbs_release_uevent(file, &uqp->uevent); 190 + kfree(uqp); 191 } 192 193 list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) {