aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorSasha Levin <levinsasha928@gmail.com>2012-04-28 01:40:01 -0400
committerRoland Dreier <roland@purestorage.com>2012-05-08 14:17:48 -0400
commit3e4d60a82e7ab4cd6e212b6834c6a48c79731957 (patch)
tree9e03784ae5e92144ac5b19a8e76d0342118162c9 /drivers
parentc592c42331f685b73f19ee54cfebfac0084f6e93 (diff)
RDMA/ocrdma: Don't sleep in atomic notifier handler
Events sent to ocrdma_inet6addr_event() are sent from an atomic context, therefore we can't try to lock a mutex within the notifier callback. We could just switch the mutex to a spinlock since all it does it protect a list, but I've gone ahead and switched the list to use RCU instead. I couldn't fully test it since I don't have IB hardware, so if it doesn't fully work for some reason let me know and I'll switch it back to using a spinlock. Signed-off-by: Sasha Levin <levinsasha928@gmail.com> [ Fixed locking in ocrdma_add(). - Roland ] Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma.h1
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_main.c38
2 files changed, 23 insertions, 16 deletions
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma.h b/drivers/infiniband/hw/ocrdma/ocrdma.h
index d7a44b812dfc..85a69c958559 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma.h
@@ -168,6 +168,7 @@ struct ocrdma_dev {
168 struct be_dev_info nic_info; 168 struct be_dev_info nic_info;
169 169
170 struct list_head entry; 170 struct list_head entry;
171 struct rcu_head rcu;
171 int id; 172 int id;
172}; 173};
173 174
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
index cee201ed14ae..0bc1efb02ff5 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
@@ -47,7 +47,7 @@ MODULE_AUTHOR("Emulex Corporation");
47MODULE_LICENSE("GPL"); 47MODULE_LICENSE("GPL");
48 48
49static LIST_HEAD(ocrdma_dev_list); 49static LIST_HEAD(ocrdma_dev_list);
50static DEFINE_MUTEX(ocrdma_devlist_lock); 50static DEFINE_SPINLOCK(ocrdma_devlist_lock);
51static DEFINE_IDR(ocrdma_dev_id); 51static DEFINE_IDR(ocrdma_dev_id);
52 52
53static union ib_gid ocrdma_zero_sgid; 53static union ib_gid ocrdma_zero_sgid;
@@ -221,14 +221,14 @@ static int ocrdma_inet6addr_event(struct notifier_block *notifier,
221 is_vlan = true; 221 is_vlan = true;
222 vid = vlan_dev_vlan_id(event_netdev); 222 vid = vlan_dev_vlan_id(event_netdev);
223 } 223 }
224 mutex_lock(&ocrdma_devlist_lock); 224 rcu_read_lock();
225 list_for_each_entry(dev, &ocrdma_dev_list, entry) { 225 list_for_each_entry_rcu(dev, &ocrdma_dev_list, entry) {
226 if (dev->nic_info.netdev == netdev) { 226 if (dev->nic_info.netdev == netdev) {
227 found = true; 227 found = true;
228 break; 228 break;
229 } 229 }
230 } 230 }
231 mutex_unlock(&ocrdma_devlist_lock); 231 rcu_read_unlock();
232 232
233 if (!found) 233 if (!found)
234 return NOTIFY_DONE; 234 return NOTIFY_DONE;
@@ -431,9 +431,9 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
431 if (status) 431 if (status)
432 goto alloc_err; 432 goto alloc_err;
433 433
434 mutex_lock(&ocrdma_devlist_lock); 434 spin_lock(&ocrdma_devlist_lock);
435 list_add_tail(&dev->entry, &ocrdma_dev_list); 435 list_add_tail_rcu(&dev->entry, &ocrdma_dev_list);
436 mutex_unlock(&ocrdma_devlist_lock); 436 spin_unlock(&ocrdma_devlist_lock);
437 return dev; 437 return dev;
438 438
439alloc_err: 439alloc_err:
@@ -448,16 +448,9 @@ idr_err:
448 return NULL; 448 return NULL;
449} 449}
450 450
451static void ocrdma_remove(struct ocrdma_dev *dev) 451static void ocrdma_remove_free(struct rcu_head *rcu)
452{ 452{
453 /* first unregister with stack to stop all the active traffic 453 struct ocrdma_dev *dev = container_of(rcu, struct ocrdma_dev, rcu);
454 * of the registered clients.
455 */
456 ib_unregister_device(&dev->ibdev);
457
458 mutex_lock(&ocrdma_devlist_lock);
459 list_del(&dev->entry);
460 mutex_unlock(&ocrdma_devlist_lock);
461 454
462 ocrdma_free_resources(dev); 455 ocrdma_free_resources(dev);
463 ocrdma_cleanup_hw(dev); 456 ocrdma_cleanup_hw(dev);
@@ -467,6 +460,19 @@ static void ocrdma_remove(struct ocrdma_dev *dev)
467 ib_dealloc_device(&dev->ibdev); 460 ib_dealloc_device(&dev->ibdev);
468} 461}
469 462
463static void ocrdma_remove(struct ocrdma_dev *dev)
464{
465 /* first unregister with stack to stop all the active traffic
466 * of the registered clients.
467 */
468 ib_unregister_device(&dev->ibdev);
469
470 spin_lock(&ocrdma_devlist_lock);
471 list_del_rcu(&dev->entry);
472 spin_unlock(&ocrdma_devlist_lock);
473 call_rcu(&dev->rcu, ocrdma_remove_free);
474}
475
470static int ocrdma_open(struct ocrdma_dev *dev) 476static int ocrdma_open(struct ocrdma_dev *dev)
471{ 477{
472 struct ib_event port_event; 478 struct ib_event port_event;