Skip to content

Commit f4e4015

Browse files
Jack MorgensteinRoland Dreier
authored andcommitted
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 <[email protected]> Signed-off-by: Michael S. Tsirkin <[email protected]> Signed-off-by: Roland Dreier <[email protected]>
1 parent e0ae9ec commit f4e4015

File tree

3 files changed

+99
-23
lines changed

3 files changed

+99
-23
lines changed

drivers/infiniband/core/uverbs.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,23 @@ struct ib_uverbs_event {
105105
u32 *counter;
106106
};
107107

108+
struct ib_uverbs_mcast_entry {
109+
struct list_head list;
110+
union ib_gid gid;
111+
u16 lid;
112+
};
113+
108114
struct ib_uevent_object {
109115
struct ib_uobject uobject;
110116
struct list_head event_list;
111117
u32 events_reported;
112118
};
113119

120+
struct ib_uqp_object {
121+
struct ib_uevent_object uevent;
122+
struct list_head mcast_list;
123+
};
124+
114125
struct ib_ucq_object {
115126
struct ib_uobject uobject;
116127
struct ib_uverbs_file *uverbs_file;

drivers/infiniband/core/uverbs_cmd.c

Lines changed: 71 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -815,7 +815,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
815815
struct ib_uverbs_create_qp cmd;
816816
struct ib_uverbs_create_qp_resp resp;
817817
struct ib_udata udata;
818-
struct ib_uevent_object *uobj;
818+
struct ib_uqp_object *uobj;
819819
struct ib_pd *pd;
820820
struct ib_cq *scq, *rcq;
821821
struct ib_srq *srq;
@@ -866,10 +866,11 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
866866
attr.cap.max_recv_sge = cmd.max_recv_sge;
867867
attr.cap.max_inline_data = cmd.max_inline_data;
868868

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);
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);
873874

874875
qp = pd->device->create_qp(pd, &attr, &udata);
875876
if (IS_ERR(qp)) {
@@ -882,7 +883,7 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
882883
qp->send_cq = attr.send_cq;
883884
qp->recv_cq = attr.recv_cq;
884885
qp->srq = attr.srq;
885-
qp->uobject = &uobj->uobject;
886+
qp->uobject = &uobj->uevent.uobject;
886887
qp->event_handler = attr.event_handler;
887888
qp->qp_context = attr.qp_context;
888889
qp->qp_type = attr.qp_type;
@@ -901,14 +902,14 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
901902
goto err_destroy;
902903
}
903904

904-
ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->uobject.id);
905+
ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->uevent.uobject.id);
905906

906907
if (ret == -EAGAIN)
907908
goto retry;
908909
if (ret)
909910
goto err_destroy;
910911

911-
resp.qp_handle = uobj->uobject.id;
912+
resp.qp_handle = uobj->uevent.uobject.id;
912913
resp.max_recv_sge = attr.cap.max_recv_sge;
913914
resp.max_send_sge = attr.cap.max_send_sge;
914915
resp.max_recv_wr = attr.cap.max_recv_wr;
@@ -922,15 +923,15 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
922923
}
923924

924925
down(&file->mutex);
925-
list_add_tail(&uobj->uobject.list, &file->ucontext->qp_list);
926+
list_add_tail(&uobj->uevent.uobject.list, &file->ucontext->qp_list);
926927
up(&file->mutex);
927928

928929
up(&ib_uverbs_idr_mutex);
929930

930931
return in_len;
931932

932933
err_idr:
933-
idr_remove(&ib_uverbs_qp_idr, uobj->uobject.id);
934+
idr_remove(&ib_uverbs_qp_idr, uobj->uevent.uobject.id);
934935

935936
err_destroy:
936937
ib_destroy_qp(qp);
@@ -1032,7 +1033,7 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
10321033
struct ib_uverbs_destroy_qp cmd;
10331034
struct ib_uverbs_destroy_qp_resp resp;
10341035
struct ib_qp *qp;
1035-
struct ib_uevent_object *uobj;
1036+
struct ib_uqp_object *uobj;
10361037
int ret = -EINVAL;
10371038

10381039
if (copy_from_user(&cmd, buf, sizeof cmd))
@@ -1046,7 +1047,12 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
10461047
if (!qp || qp->uobject->context != file->ucontext)
10471048
goto out;
10481049

1049-
uobj = container_of(qp->uobject, struct ib_uevent_object, uobject);
1050+
uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject);
1051+
1052+
if (!list_empty(&uobj->mcast_list)) {
1053+
ret = -EBUSY;
1054+
goto out;
1055+
}
10501056

10511057
ret = ib_destroy_qp(qp);
10521058
if (ret)
@@ -1055,12 +1061,12 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
10551061
idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle);
10561062

10571063
down(&file->mutex);
1058-
list_del(&uobj->uobject.list);
1064+
list_del(&uobj->uevent.uobject.list);
10591065
up(&file->mutex);
10601066

1061-
ib_uverbs_release_uevent(file, uobj);
1067+
ib_uverbs_release_uevent(file, &uobj->uevent);
10621068

1063-
resp.events_reported = uobj->events_reported;
1069+
resp.events_reported = uobj->uevent.events_reported;
10641070

10651071
kfree(uobj);
10661072

@@ -1542,6 +1548,8 @@ ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
15421548
{
15431549
struct ib_uverbs_attach_mcast cmd;
15441550
struct ib_qp *qp;
1551+
struct ib_uqp_object *uobj;
1552+
struct ib_uverbs_mcast_entry *mcast;
15451553
int ret = -EINVAL;
15461554

15471555
if (copy_from_user(&cmd, buf, sizeof cmd))
@@ -1550,9 +1558,36 @@ ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
15501558
down(&ib_uverbs_idr_mutex);
15511559

15521560
qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
1553-
if (qp && qp->uobject->context == file->ucontext)
1554-
ret = ib_attach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid);
1561+
if (!qp || qp->uobject->context != file->ucontext)
1562+
goto out;
1563+
1564+
uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject);
1565+
1566+
list_for_each_entry(mcast, &uobj->mcast_list, list)
1567+
if (cmd.mlid == mcast->lid &&
1568+
!memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) {
1569+
ret = 0;
1570+
goto out;
1571+
}
15551572

1573+
mcast = kmalloc(sizeof *mcast, GFP_KERNEL);
1574+
if (!mcast) {
1575+
ret = -ENOMEM;
1576+
goto out;
1577+
}
1578+
1579+
mcast->lid = cmd.mlid;
1580+
memcpy(mcast->gid.raw, cmd.gid, sizeof mcast->gid.raw);
1581+
1582+
ret = ib_attach_mcast(qp, &mcast->gid, cmd.mlid);
1583+
if (!ret) {
1584+
uobj = container_of(qp->uobject, struct ib_uqp_object,
1585+
uevent.uobject);
1586+
list_add_tail(&mcast->list, &uobj->mcast_list);
1587+
} else
1588+
kfree(mcast);
1589+
1590+
out:
15561591
up(&ib_uverbs_idr_mutex);
15571592

15581593
return ret ? ret : in_len;
@@ -1563,7 +1598,9 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
15631598
int out_len)
15641599
{
15651600
struct ib_uverbs_detach_mcast cmd;
1601+
struct ib_uqp_object *uobj;
15661602
struct ib_qp *qp;
1603+
struct ib_uverbs_mcast_entry *mcast;
15671604
int ret = -EINVAL;
15681605

15691606
if (copy_from_user(&cmd, buf, sizeof cmd))
@@ -1572,9 +1609,24 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
15721609
down(&ib_uverbs_idr_mutex);
15731610

15741611
qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
1575-
if (qp && qp->uobject->context == file->ucontext)
1576-
ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid);
1612+
if (!qp || qp->uobject->context != file->ucontext)
1613+
goto out;
1614+
1615+
ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid);
1616+
if (ret)
1617+
goto out;
15771618

1619+
uobj = container_of(qp->uobject, struct ib_uqp_object, uevent.uobject);
1620+
1621+
list_for_each_entry(mcast, &uobj->mcast_list, list)
1622+
if (cmd.mlid == mcast->lid &&
1623+
!memcmp(cmd.gid, mcast->gid.raw, sizeof mcast->gid.raw)) {
1624+
list_del(&mcast->list);
1625+
kfree(mcast);
1626+
break;
1627+
}
1628+
1629+
out:
15781630
up(&ib_uverbs_idr_mutex);
15791631

15801632
return ret ? ret : in_len;

drivers/infiniband/core/uverbs_main.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,18 @@ void ib_uverbs_release_uevent(struct ib_uverbs_file *file,
160160
spin_unlock_irq(&file->async_file->lock);
161161
}
162162

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+
163175
static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
164176
struct ib_ucontext *context)
165177
{
@@ -180,13 +192,14 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
180192

181193
list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) {
182194
struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id);
183-
struct ib_uevent_object *uevent =
184-
container_of(uobj, struct ib_uevent_object, uobject);
195+
struct ib_uqp_object *uqp =
196+
container_of(uobj, struct ib_uqp_object, uevent.uobject);
185197
idr_remove(&ib_uverbs_qp_idr, uobj->id);
198+
ib_uverbs_detach_umcast(qp, uqp);
186199
ib_destroy_qp(qp);
187200
list_del(&uobj->list);
188-
ib_uverbs_release_uevent(file, uevent);
189-
kfree(uevent);
201+
ib_uverbs_release_uevent(file, &uqp->uevent);
202+
kfree(uqp);
190203
}
191204

192205
list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) {

0 commit comments

Comments
 (0)