]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
sdp: fix lockup on mthca cards
authorAmir Vadai <amirv@mellanox.co.il>
Mon, 7 Dec 2009 13:31:58 +0000 (15:31 +0200)
committerMukesh Kacker <mukesh.kacker@oracle.com>
Tue, 6 Oct 2015 12:04:44 +0000 (05:04 -0700)
- 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 <amirv@mellanox.co.il>
drivers/infiniband/ulp/sdp/sdp.h
drivers/infiniband/ulp/sdp/sdp_rx.c

index 3bbabd21a2c1f7ccc05e85319c5727f73b082f2e..09bea871135220512ba49ea29cd339f6df92c500 100644 (file)
@@ -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)
index 3e65b2608cb65e7f606c3c7ef7a8954bbf354597..e6dd79f75b0b2929bb1741fb7efd98b9b69dae65 100644 (file)
@@ -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);