diff mbox series

[v6,2/4] rdma_rxe: schedule rxe_net_remove()

Message ID e4bae2590179ddafe14260a4212ec8f65f972aa9.1544033819.git.swise@opengridcomputing.com (mailing list archive)
State Superseded
Headers show
Series Dynamic rdma link creation | expand

Commit Message

Steve Wise Dec. 5, 2018, 3:14 p.m. UTC
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@opengridcomputing.com>
---
 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 mbox series

Patch

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)