Schedule rxe_net_remove() 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 | 12 +++++++++++- drivers/infiniband/sw/rxe/rxe_net.h | 1 + drivers/infiniband/sw/rxe/rxe_verbs.h | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/sw/rxe/rxe.c b/drivers/infiniband/sw/rxe/rxe.c index 971f0862cefe..19d8e522b72b 100644 --- a/drivers/infiniband/sw/rxe/rxe.c +++ b/drivers/infiniband/sw/rxe/rxe.c @@ -280,6 +280,7 @@ static int rxe_init(struct rxe_dev *rxe) spin_lock_init(&rxe->pending_lock); INIT_LIST_HEAD(&rxe->pending_mmaps); INIT_LIST_HEAD(&rxe->list); + INIT_WORK(&rxe->net_remove_work, rxe_process_net_remove); mutex_init(&rxe->usdev_lock); diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c index 6dc1a5b20e31..f1b559d728b6 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -643,6 +643,15 @@ void rxe_port_down(struct rxe_dev *rxe) dev_info(&rxe->ib_dev.dev, "set down\n"); } +void rxe_process_net_remove(struct work_struct *work) +{ + struct rxe_dev *rxe; + + rxe = container_of(work, struct rxe_dev, net_remove_work); + rxe_net_remove(rxe); + rxe_dev_put(rxe); +} + static int rxe_notify(struct notifier_block *not_blk, unsigned long event, void *arg) @@ -655,7 +664,8 @@ static int rxe_notify(struct notifier_block *not_blk, switch (event) { case NETDEV_UNREGISTER: - rxe_net_remove(rxe); + kref_get(&rxe->ref_cnt); + schedule_work(&rxe->net_remove_work); break; case NETDEV_UP: rxe_port_up(rxe); diff --git a/drivers/infiniband/sw/rxe/rxe_net.h b/drivers/infiniband/sw/rxe/rxe_net.h index 222234a8d525..feb1d715468c 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.h +++ b/drivers/infiniband/sw/rxe/rxe_net.h @@ -48,5 +48,6 @@ struct rxe_recv_sockets { int rxe_net_init(void); void rxe_net_exit(void); +void rxe_process_net_remove(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 831381b7788d..32c8ecb707d1 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.h +++ b/drivers/infiniband/sw/rxe/rxe_verbs.h @@ -414,6 +414,7 @@ struct rxe_dev { struct rxe_port port; struct list_head list; struct crypto_shash *tfm; + struct work_struct net_remove_work; }; static inline void rxe_counter_inc(struct rxe_dev *rxe, enum rxe_counters cnt) -- 1.8.3.1