aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/core/uverbs_main.c
diff options
context:
space:
mode:
authorRoland Dreier <rolandd@cisco.com>2006-06-17 23:44:49 -0400
committerRoland Dreier <rolandd@cisco.com>2006-06-17 23:44:49 -0400
commit9ead190bfde2a434c74ea604382d08acb2eceef5 (patch)
tree937f1bb8dedea56efc46aed12370bb3865898763 /drivers/infiniband/core/uverbs_main.c
parentc93b6fbaa99bb3a1552e14317296be14dde51dfb (diff)
IB/uverbs: Don't serialize with ib_uverbs_idr_mutex
Currently, all userspace verbs operations that call into the kernel are serialized by ib_uverbs_idr_mutex. This can be a scalability issue for some workloads, especially for devices driven by the ipath driver, which needs to call into the kernel even for datapath operations. Fix this by adding reference counts to the userspace objects, and then converting ib_uverbs_idr_mutex into a spinlock that only protects the idrs long enough to take a reference on the object being looked up. Because remove operations may fail, we have to do a slightly funky two-step deletion, which is described in the comments at the top of uverbs_cmd.c. This also still leaves ib_uverbs_idr_lock as a single lock that is possibly subject to contention. However, the lock hold time will only be a single idr operation, so multiple threads should still be able to make progress, even if ib_uverbs_idr_lock is being ping-ponged. Surprisingly, these changes even shrink the object code: add/remove: 23/5 grow/shrink: 4/21 up/down: 633/-693 (-60) Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/core/uverbs_main.c')
-rw-r--r--drivers/infiniband/core/uverbs_main.c35
1 files changed, 18 insertions, 17 deletions
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index ff092a0a94da..5ec2d49e9bb6 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -66,7 +66,7 @@ enum {
66 66
67static struct class *uverbs_class; 67static struct class *uverbs_class;
68 68
69DEFINE_MUTEX(ib_uverbs_idr_mutex); 69DEFINE_SPINLOCK(ib_uverbs_idr_lock);
70DEFINE_IDR(ib_uverbs_pd_idr); 70DEFINE_IDR(ib_uverbs_pd_idr);
71DEFINE_IDR(ib_uverbs_mr_idr); 71DEFINE_IDR(ib_uverbs_mr_idr);
72DEFINE_IDR(ib_uverbs_mw_idr); 72DEFINE_IDR(ib_uverbs_mw_idr);
@@ -183,21 +183,21 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
183 if (!context) 183 if (!context)
184 return 0; 184 return 0;
185 185
186 mutex_lock(&ib_uverbs_idr_mutex);
187
188 list_for_each_entry_safe(uobj, tmp, &context->ah_list, list) { 186 list_for_each_entry_safe(uobj, tmp, &context->ah_list, list) {
189 struct ib_ah *ah = idr_find(&ib_uverbs_ah_idr, uobj->id); 187 struct ib_ah *ah = uobj->object;
190 idr_remove(&ib_uverbs_ah_idr, uobj->id); 188
189 idr_remove_uobj(&ib_uverbs_ah_idr, uobj);
191 ib_destroy_ah(ah); 190 ib_destroy_ah(ah);
192 list_del(&uobj->list); 191 list_del(&uobj->list);
193 kfree(uobj); 192 kfree(uobj);
194 } 193 }
195 194
196 list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { 195 list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) {
197 struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id); 196 struct ib_qp *qp = uobj->object;
198 struct ib_uqp_object *uqp = 197 struct ib_uqp_object *uqp =
199 container_of(uobj, struct ib_uqp_object, uevent.uobject); 198 container_of(uobj, struct ib_uqp_object, uevent.uobject);
200 idr_remove(&ib_uverbs_qp_idr, uobj->id); 199
200 idr_remove_uobj(&ib_uverbs_qp_idr, uobj);
201 ib_uverbs_detach_umcast(qp, uqp); 201 ib_uverbs_detach_umcast(qp, uqp);
202 ib_destroy_qp(qp); 202 ib_destroy_qp(qp);
203 list_del(&uobj->list); 203 list_del(&uobj->list);
@@ -206,11 +206,12 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
206 } 206 }
207 207
208 list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) { 208 list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) {
209 struct ib_cq *cq = idr_find(&ib_uverbs_cq_idr, uobj->id); 209 struct ib_cq *cq = uobj->object;
210 struct ib_uverbs_event_file *ev_file = cq->cq_context; 210 struct ib_uverbs_event_file *ev_file = cq->cq_context;
211 struct ib_ucq_object *ucq = 211 struct ib_ucq_object *ucq =
212 container_of(uobj, struct ib_ucq_object, uobject); 212 container_of(uobj, struct ib_ucq_object, uobject);
213 idr_remove(&ib_uverbs_cq_idr, uobj->id); 213
214 idr_remove_uobj(&ib_uverbs_cq_idr, uobj);
214 ib_destroy_cq(cq); 215 ib_destroy_cq(cq);
215 list_del(&uobj->list); 216 list_del(&uobj->list);
216 ib_uverbs_release_ucq(file, ev_file, ucq); 217 ib_uverbs_release_ucq(file, ev_file, ucq);
@@ -218,10 +219,11 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
218 } 219 }
219 220
220 list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) { 221 list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) {
221 struct ib_srq *srq = idr_find(&ib_uverbs_srq_idr, uobj->id); 222 struct ib_srq *srq = uobj->object;
222 struct ib_uevent_object *uevent = 223 struct ib_uevent_object *uevent =
223 container_of(uobj, struct ib_uevent_object, uobject); 224 container_of(uobj, struct ib_uevent_object, uobject);
224 idr_remove(&ib_uverbs_srq_idr, uobj->id); 225
226 idr_remove_uobj(&ib_uverbs_srq_idr, uobj);
225 ib_destroy_srq(srq); 227 ib_destroy_srq(srq);
226 list_del(&uobj->list); 228 list_del(&uobj->list);
227 ib_uverbs_release_uevent(file, uevent); 229 ib_uverbs_release_uevent(file, uevent);
@@ -231,11 +233,11 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
231 /* XXX Free MWs */ 233 /* XXX Free MWs */
232 234
233 list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) { 235 list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) {
234 struct ib_mr *mr = idr_find(&ib_uverbs_mr_idr, uobj->id); 236 struct ib_mr *mr = uobj->object;
235 struct ib_device *mrdev = mr->device; 237 struct ib_device *mrdev = mr->device;
236 struct ib_umem_object *memobj; 238 struct ib_umem_object *memobj;
237 239
238 idr_remove(&ib_uverbs_mr_idr, uobj->id); 240 idr_remove_uobj(&ib_uverbs_mr_idr, uobj);
239 ib_dereg_mr(mr); 241 ib_dereg_mr(mr);
240 242
241 memobj = container_of(uobj, struct ib_umem_object, uobject); 243 memobj = container_of(uobj, struct ib_umem_object, uobject);
@@ -246,15 +248,14 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
246 } 248 }
247 249
248 list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) { 250 list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) {
249 struct ib_pd *pd = idr_find(&ib_uverbs_pd_idr, uobj->id); 251 struct ib_pd *pd = uobj->object;
250 idr_remove(&ib_uverbs_pd_idr, uobj->id); 252
253 idr_remove_uobj(&ib_uverbs_pd_idr, uobj);
251 ib_dealloc_pd(pd); 254 ib_dealloc_pd(pd);
252 list_del(&uobj->list); 255 list_del(&uobj->list);
253 kfree(uobj); 256 kfree(uobj);
254 } 257 }
255 258
256 mutex_unlock(&ib_uverbs_idr_mutex);
257
258 return context->device->dealloc_ucontext(context); 259 return context->device->dealloc_ucontext(context);
259} 260}
260 261