diff options
author | Sasha Levin <levinsasha928@gmail.com> | 2012-04-28 01:40:01 -0400 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2012-05-08 14:17:48 -0400 |
commit | 3e4d60a82e7ab4cd6e212b6834c6a48c79731957 (patch) | |
tree | 9e03784ae5e92144ac5b19a8e76d0342118162c9 /drivers/infiniband | |
parent | c592c42331f685b73f19ee54cfebfac0084f6e93 (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/infiniband')
-rw-r--r-- | drivers/infiniband/hw/ocrdma/ocrdma.h | 1 | ||||
-rw-r--r-- | drivers/infiniband/hw/ocrdma/ocrdma_main.c | 38 |
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"); | |||
47 | MODULE_LICENSE("GPL"); | 47 | MODULE_LICENSE("GPL"); |
48 | 48 | ||
49 | static LIST_HEAD(ocrdma_dev_list); | 49 | static LIST_HEAD(ocrdma_dev_list); |
50 | static DEFINE_MUTEX(ocrdma_devlist_lock); | 50 | static DEFINE_SPINLOCK(ocrdma_devlist_lock); |
51 | static DEFINE_IDR(ocrdma_dev_id); | 51 | static DEFINE_IDR(ocrdma_dev_id); |
52 | 52 | ||
53 | static union ib_gid ocrdma_zero_sgid; | 53 | static 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 | ||
439 | alloc_err: | 439 | alloc_err: |
@@ -448,16 +448,9 @@ idr_err: | |||
448 | return NULL; | 448 | return NULL; |
449 | } | 449 | } |
450 | 450 | ||
451 | static void ocrdma_remove(struct ocrdma_dev *dev) | 451 | static 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 | ||
463 | static 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 | |||
470 | static int ocrdma_open(struct ocrdma_dev *dev) | 476 | static int ocrdma_open(struct ocrdma_dev *dev) |
471 | { | 477 | { |
472 | struct ib_event port_event; | 478 | struct ib_event port_event; |