From: Amir Vadai Date: Mon, 7 Dec 2009 13:31:58 +0000 (+0200) Subject: sdp: fix lockup on mthca cards X-Git-Tag: v4.1.12-92~264^2~5^2~230 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=26daa321e6ae93215e36c86e6794936069807d37;p=users%2Fjedix%2Flinux-maple.git sdp: fix lockup on mthca cards - rx_irq called sdp_sock_queue_rcv_skb() who calls sk->sk_data_ready() == sock_def_readable - sock_def_readable() can't be called from interrupt context because it takes read_lock (the writer to the lock uses write_lock_bh) - moved rx processing to tasklet sock_def_readable was trying to take read_lock Signed-off-by: Amir Vadai --- diff --git a/drivers/infiniband/ulp/sdp/sdp.h b/drivers/infiniband/ulp/sdp/sdp.h index 3bbabd21a2c1..09bea8711352 100644 --- a/drivers/infiniband/ulp/sdp/sdp.h +++ b/drivers/infiniband/ulp/sdp/sdp.h @@ -277,6 +277,8 @@ struct sdp_rx_ring { int destroyed; rwlock_t destroyed_lock; + + struct tasklet_struct tasklet; }; struct sdp_device { @@ -414,18 +416,16 @@ static inline void tx_sa_reset(struct tx_srcavail_state *tx_sa) sizeof(*tx_sa) - offsetof(typeof(*tx_sa), busy)); } -static inline void rx_ring_unlock(struct sdp_rx_ring *rx_ring, - unsigned long *flags) +static inline void rx_ring_unlock(struct sdp_rx_ring *rx_ring) { - read_unlock_irqrestore(&rx_ring->destroyed_lock, *flags); + read_unlock_bh(&rx_ring->destroyed_lock); } -static inline int rx_ring_trylock(struct sdp_rx_ring *rx_ring, - unsigned long *flags) +static inline int rx_ring_trylock(struct sdp_rx_ring *rx_ring) { - read_lock_irqsave(&rx_ring->destroyed_lock, *flags); + read_lock_bh(&rx_ring->destroyed_lock); if (rx_ring->destroyed) { - rx_ring_unlock(rx_ring, flags); + rx_ring_unlock(rx_ring); return 0; } return 1; @@ -433,11 +433,9 @@ static inline int rx_ring_trylock(struct sdp_rx_ring *rx_ring, static inline void rx_ring_destroy_lock(struct sdp_rx_ring *rx_ring) { - unsigned long flags; - - write_lock_irqsave(&rx_ring->destroyed_lock, flags); + write_lock_bh(&rx_ring->destroyed_lock); rx_ring->destroyed = 1; - write_unlock_irqrestore(&rx_ring->destroyed_lock, flags); + write_unlock_bh(&rx_ring->destroyed_lock); } static inline struct sdp_sock *sdp_sk(const struct sock *sk) diff --git a/drivers/infiniband/ulp/sdp/sdp_rx.c b/drivers/infiniband/ulp/sdp/sdp_rx.c index 3e65b2608cb6..e6dd79f75b0b 100644 --- a/drivers/infiniband/ulp/sdp/sdp_rx.c +++ b/drivers/infiniband/ulp/sdp/sdp_rx.c @@ -798,9 +798,6 @@ static void sdp_rx_irq(struct ib_cq *cq, void *cq_context) { struct sock *sk = cq_context; struct sdp_sock *ssk = sdp_sk(sk); - unsigned long flags; - int wc_processed = 0; - int credits_before; if (cq != ssk->rx_ring.cq) { sdp_dbg(sk, "cq = %p, ssk->cq = %p\n", cq, ssk->rx_ring.cq); @@ -811,7 +808,17 @@ static void sdp_rx_irq(struct ib_cq *cq, void *cq_context) sdp_prf(sk, NULL, "rx irq"); - if (!rx_ring_trylock(&ssk->rx_ring, &flags)) { + tasklet_hi_schedule(&ssk->rx_ring.tasklet); +} + +static void sdp_process_rx(unsigned long data) +{ + struct sdp_sock *ssk = (struct sdp_sock *)data; + struct sock *sk = &ssk->isk.sk; + int wc_processed = 0; + int credits_before; + + if (!rx_ring_trylock(&ssk->rx_ring)) { sdp_dbg(&ssk->isk.sk, "ring destroyed. not polling it\n"); return; } @@ -840,7 +847,7 @@ static void sdp_rx_irq(struct ib_cq *cq, void *cq_context) } sdp_arm_rx_cq(sk); - rx_ring_unlock(&ssk->rx_ring, &flags); + rx_ring_unlock(&ssk->rx_ring); } static void sdp_rx_ring_purge(struct sdp_sock *ssk) @@ -898,6 +905,8 @@ int sdp_rx_ring_create(struct sdp_sock *ssk, struct ib_device *device) sdp_sk(&ssk->isk.sk)->rx_ring.cq = rx_cq; INIT_WORK(&ssk->rx_comp_work, sdp_rx_comp_work); + tasklet_init(&ssk->rx_ring.tasklet, sdp_process_rx, + (unsigned long) ssk); sdp_arm_rx_cq(&ssk->isk.sk);