@@ -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);
@@ -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);
@@ -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 */
@@ -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)
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(-)