aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/hw
diff options
context:
space:
mode:
authorRoland Dreier <rolandd@cisco.com>2007-05-19 11:51:53 -0400
committerRoland Dreier <rolandd@cisco.com>2007-05-19 11:51:53 -0400
commit8b8c8bca3a63073bac20f0fca178e00fdf7f5a09 (patch)
tree59c7f4b6a502e99e620d20d9c251fdebb79cc34a /drivers/infiniband/hw
parent7b82cd8ee7374f803a3daf9a6cbc6eb4bbb10a63 (diff)
IB/ipath: Fix potential deadlock with multicast spinlocks
Lockdep found the following potential deadlock between mcast_lock and n_mcast_grps_lock: mcast_lock is taken from both interrupt context and process context, so spin_lock_irqsave() must be used to take it. n_mcast_grps_lock is only taken from process context, so at first it seems safe to take it with plain spin_lock(); however, it also nests inside mcast_lock, and hence we could deadlock: cpu A cpu B ipath_mcast_add(): spin_lock_irq(&mcast_lock); ipath_mcast_detach(): spin_lock(&n_mcast_grps_lock); <enter interrupt> ipath_mcast_find(): spin_lock_irqsave(&mcast_lock); spin_lock(&n_mcast_grps_lock); Fix this by using spin_lock_irq() to take n_mcast_grps_lock. Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw')
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs_mcast.c16
1 files changed, 7 insertions, 9 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c b/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c
index 085e28b939ec..dd691cfa5079 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c
@@ -165,10 +165,9 @@ static int ipath_mcast_add(struct ipath_ibdev *dev,
165{ 165{
166 struct rb_node **n = &mcast_tree.rb_node; 166 struct rb_node **n = &mcast_tree.rb_node;
167 struct rb_node *pn = NULL; 167 struct rb_node *pn = NULL;
168 unsigned long flags;
169 int ret; 168 int ret;
170 169
171 spin_lock_irqsave(&mcast_lock, flags); 170 spin_lock_irq(&mcast_lock);
172 171
173 while (*n) { 172 while (*n) {
174 struct ipath_mcast *tmcast; 173 struct ipath_mcast *tmcast;
@@ -228,7 +227,7 @@ static int ipath_mcast_add(struct ipath_ibdev *dev,
228 ret = 0; 227 ret = 0;
229 228
230bail: 229bail:
231 spin_unlock_irqrestore(&mcast_lock, flags); 230 spin_unlock_irq(&mcast_lock);
232 231
233 return ret; 232 return ret;
234} 233}
@@ -289,17 +288,16 @@ int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
289 struct ipath_mcast *mcast = NULL; 288 struct ipath_mcast *mcast = NULL;
290 struct ipath_mcast_qp *p, *tmp; 289 struct ipath_mcast_qp *p, *tmp;
291 struct rb_node *n; 290 struct rb_node *n;
292 unsigned long flags;
293 int last = 0; 291 int last = 0;
294 int ret; 292 int ret;
295 293
296 spin_lock_irqsave(&mcast_lock, flags); 294 spin_lock_irq(&mcast_lock);
297 295
298 /* Find the GID in the mcast table. */ 296 /* Find the GID in the mcast table. */
299 n = mcast_tree.rb_node; 297 n = mcast_tree.rb_node;
300 while (1) { 298 while (1) {
301 if (n == NULL) { 299 if (n == NULL) {
302 spin_unlock_irqrestore(&mcast_lock, flags); 300 spin_unlock_irq(&mcast_lock);
303 ret = -EINVAL; 301 ret = -EINVAL;
304 goto bail; 302 goto bail;
305 } 303 }
@@ -334,7 +332,7 @@ int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
334 break; 332 break;
335 } 333 }
336 334
337 spin_unlock_irqrestore(&mcast_lock, flags); 335 spin_unlock_irq(&mcast_lock);
338 336
339 if (p) { 337 if (p) {
340 /* 338 /*
@@ -348,9 +346,9 @@ int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
348 atomic_dec(&mcast->refcount); 346 atomic_dec(&mcast->refcount);
349 wait_event(mcast->wait, !atomic_read(&mcast->refcount)); 347 wait_event(mcast->wait, !atomic_read(&mcast->refcount));
350 ipath_mcast_free(mcast); 348 ipath_mcast_free(mcast);
351 spin_lock(&dev->n_mcast_grps_lock); 349 spin_lock_irq(&dev->n_mcast_grps_lock);
352 dev->n_mcast_grps_allocated--; 350 dev->n_mcast_grps_allocated--;
353 spin_unlock(&dev->n_mcast_grps_lock); 351 spin_unlock_irq(&dev->n_mcast_grps_lock);
354 } 352 }
355 353
356 ret = 0; 354 ret = 0;