@@ -272,6 +272,7 @@ static int rxe_init(struct rxe_dev *rxe)
spin_lock_init(&rxe->mmap_offset_lock);
spin_lock_init(&rxe->pending_lock);
INIT_LIST_HEAD(&rxe->pending_mmaps);
+ INIT_WORK(&rxe->netdev_unregister_work, rxe_netdev_unregister_work);
mutex_init(&rxe->usdev_lock);
@@ -585,6 +585,14 @@ void rxe_set_port_state(struct net_device *ndev, struct rxe_dev *rxe)
rxe_port_down(rxe);
}
+void rxe_netdev_unregister_work(struct work_struct *work)
+{
+ struct rxe_dev *rxe;
+
+ rxe = container_of(work, struct rxe_dev, netdev_unregister_work);
+ ib_unregister_device_and_put(&rxe->ib_dev);
+}
+
static int rxe_notify(struct notifier_block *not_blk,
unsigned long event,
void *arg)
@@ -597,7 +605,7 @@ static int rxe_notify(struct notifier_block *not_blk,
switch (event) {
case NETDEV_UNREGISTER:
- ib_unregister_device_and_put(&rxe->ib_dev);
+ schedule_work(&rxe->netdev_unregister_work);
return NOTIFY_OK;
case NETDEV_UP:
@@ -47,5 +47,6 @@ struct rxe_recv_sockets {
int rxe_net_init(void);
void rxe_net_exit(void);
+void rxe_netdev_unregister_work(struct work_struct *work);
#endif /* RXE_NET_H */
@@ -412,6 +412,7 @@ struct rxe_dev {
struct rxe_port port;
struct crypto_shash *tfm;
+ struct work_struct netdev_unregister_work;
};
static inline void rxe_counter_inc(struct rxe_dev *rxe, enum rxe_counters cnt)
Schedule ib_unregister_device_and_put() to run in a workqueue context to avoid a deadlock when processing NETDEV_UNREGISTER events. Signed-off-by: Steve Wise <swise@opengridcomputing.com> --- drivers/infiniband/sw/rxe/rxe.c | 1 + drivers/infiniband/sw/rxe/rxe_net.c | 10 +++++++++- drivers/infiniband/sw/rxe/rxe_net.h | 1 + drivers/infiniband/sw/rxe/rxe_verbs.h | 1 + 4 files changed, 12 insertions(+), 1 deletion(-)