aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorEli Cohen <eli@dev.mellanox.co.il>2012-01-03 23:36:48 -0500
committerRoland Dreier <roland@purestorage.com>2012-01-03 23:36:48 -0500
commite214a0fe2b382fa302c036ecd6e6ffe99e3b9875 (patch)
tree6cfd92715630e3406521f700a3df3cf3295e7770 /drivers/infiniband
parent5f0a6e2d503896062f641639dacfe5055c2f593b (diff)
IB/uverbs: Protect QP multicast list
Userspace verbs multicast attach/detach operations on a QP are done while holding the rwsem of the QP for reading. That's not sufficient since a reader lock allows more than one reader to acquire the lock. However, multicast attach/detach does list manipulation that can corrupt the list if multiple threads run in parallel. Fix this by acquiring the rwsem as a writer to serialize attach/detach operations. Add idr_write_qp() and put_qp_write() to encapsulate this. This fixes oops seen when running applications that perform multicast joins/leaves. Reported by: Mike Dubman <miked@mellanox.com> Signed-off-by: Eli Cohen <eli@mellanox.com> Cc: <stable@kernel.org> Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c21
1 files changed, 17 insertions, 4 deletions
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 254f1649c734..e3db8ef4fe4e 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -241,11 +241,24 @@ static struct ib_qp *idr_read_qp(int qp_handle, struct ib_ucontext *context)
241 return idr_read_obj(&ib_uverbs_qp_idr, qp_handle, context, 0); 241 return idr_read_obj(&ib_uverbs_qp_idr, qp_handle, context, 0);
242} 242}
243 243
244static struct ib_qp *idr_write_qp(int qp_handle, struct ib_ucontext *context)
245{
246 struct ib_uobject *uobj;
247
248 uobj = idr_write_uobj(&ib_uverbs_qp_idr, qp_handle, context);
249 return uobj ? uobj->object : NULL;
250}
251
244static void put_qp_read(struct ib_qp *qp) 252static void put_qp_read(struct ib_qp *qp)
245{ 253{
246 put_uobj_read(qp->uobject); 254 put_uobj_read(qp->uobject);
247} 255}
248 256
257static void put_qp_write(struct ib_qp *qp)
258{
259 put_uobj_write(qp->uobject);
260}
261
249static struct ib_srq *idr_read_srq(int srq_handle, struct ib_ucontext *context) 262static struct ib_srq *idr_read_srq(int srq_handle, struct ib_ucontext *context)
250{ 263{
251 return idr_read_obj(&ib_uverbs_srq_idr, srq_handle, context, 0); 264 return idr_read_obj(&ib_uverbs_srq_idr, srq_handle, context, 0);
@@ -2375,7 +2388,7 @@ ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
2375 if (copy_from_user(&cmd, buf, sizeof cmd)) 2388 if (copy_from_user(&cmd, buf, sizeof cmd))
2376 return -EFAULT; 2389 return -EFAULT;
2377 2390
2378 qp = idr_read_qp(cmd.qp_handle, file->ucontext); 2391 qp = idr_write_qp(cmd.qp_handle, file->ucontext);
2379 if (!qp) 2392 if (!qp)
2380 return -EINVAL; 2393 return -EINVAL;
2381 2394
@@ -2404,7 +2417,7 @@ ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
2404 kfree(mcast); 2417 kfree(mcast);
2405 2418
2406out_put: 2419out_put:
2407 put_qp_read(qp); 2420 put_qp_write(qp);
2408 2421
2409 return ret ? ret : in_len; 2422 return ret ? ret : in_len;
2410} 2423}
@@ -2422,7 +2435,7 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
2422 if (copy_from_user(&cmd, buf, sizeof cmd)) 2435 if (copy_from_user(&cmd, buf, sizeof cmd))
2423 return -EFAULT; 2436 return -EFAULT;
2424 2437
2425 qp = idr_read_qp(cmd.qp_handle, file->ucontext); 2438 qp = idr_write_qp(cmd.qp_handle, file->ucontext);
2426 if (!qp) 2439 if (!qp)
2427 return -EINVAL; 2440 return -EINVAL;
2428 2441
@@ -2441,7 +2454,7 @@ ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
2441 } 2454 }
2442 2455
2443out_put: 2456out_put:
2444 put_qp_read(qp); 2457 put_qp_write(qp);
2445 2458
2446 return ret ? ret : in_len; 2459 return ret ? ret : in_len;
2447} 2460}