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@xxxxxxxxxxxxxxxxxxxxx> --- 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(-) diff --git a/drivers/infiniband/sw/rxe/rxe.c b/drivers/infiniband/sw/rxe/rxe.c index 4069463f9a66..91ad339fd6e1 100644 --- a/drivers/infiniband/sw/rxe/rxe.c +++ b/drivers/infiniband/sw/rxe/rxe.c @@ -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); diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c index 6a25b514d448..c05549d09268 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -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: diff --git a/drivers/infiniband/sw/rxe/rxe_net.h b/drivers/infiniband/sw/rxe/rxe_net.h index 106c586dbb26..685aa98baf55 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.h +++ b/drivers/infiniband/sw/rxe/rxe_net.h @@ -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 */ diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.h b/drivers/infiniband/sw/rxe/rxe_verbs.h index a0b635812784..ce63cbf0d738 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.h +++ b/drivers/infiniband/sw/rxe/rxe_verbs.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) -- 1.8.3.1