IB/rxe: Hold refs when running tasklets
authorAndrew Boyer <andrew.boyer@dell.com>
Mon, 5 Dec 2016 13:43:21 +0000 (08:43 -0500)
committerDoug Ledford <dledford@redhat.com>
Mon, 12 Dec 2016 21:34:22 +0000 (16:34 -0500)
It might be possible for all of a QP's references to be dropped
while one of that QP's tasklets is running.

For example, the completer might run during QP destroy.
If qp->valid is false, it will drop all of the packets on
the resp_pkts list, potentially removing the last reference.
Then it tries to advance the SQ consumer pointer. If the
SQ's buffer has already been destroyed, the system will
panic.

To be safe, hold a reference on the QP for the duration
of each tasklet.

Signed-off-by: Andrew Boyer <andrew.boyer@dell.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/sw/rxe/rxe_comp.c
drivers/infiniband/sw/rxe/rxe_req.c
drivers/infiniband/sw/rxe/rxe_resp.c

index d46c49b33b13d123f6c24e39410fd7ffbe2d6429..cd27cbde765249b98331fd1da8f023d134dddd38 100644 (file)
@@ -511,6 +511,8 @@ int rxe_completer(void *arg)
        struct rxe_pkt_info *pkt = NULL;
        enum comp_state state;
 
+       rxe_add_ref(qp);
+
        if (!qp->valid) {
                while ((skb = skb_dequeue(&qp->resp_pkts))) {
                        rxe_drop_ref(qp);
@@ -740,11 +742,13 @@ exit:
        /* we come here if we are done with processing and want the task to
         * exit from the loop calling us
         */
+       rxe_drop_ref(qp);
        return -EAGAIN;
 
 done:
        /* we come here if we have processed a packet we want the task to call
         * us again to see if there is anything else to do
         */
+       rxe_drop_ref(qp);
        return 0;
 }
index 205222909e53d982275bd5b059d12234fb69aff6..b246653cf713e7fd5b5d507426d308e55ea3bf9c 100644 (file)
@@ -596,6 +596,8 @@ int rxe_requester(void *arg)
        struct rxe_send_wqe rollback_wqe;
        u32 rollback_psn;
 
+       rxe_add_ref(qp);
+
 next_wqe:
        if (unlikely(!qp->valid || qp->req.state == QP_STATE_ERROR))
                goto exit;
@@ -750,9 +752,10 @@ complete:
                while (rxe_completer(qp) == 0)
                        ;
        }
-
+       rxe_drop_ref(qp);
        return 0;
 
 exit:
+       rxe_drop_ref(qp);
        return -EAGAIN;
 }
index 8643797fb530f5bdc3f8524496a389c4ab86e1a5..7a36ec9dbc0c98cc9907f378e593814fbe26ffcc 100644 (file)
@@ -1212,6 +1212,8 @@ int rxe_responder(void *arg)
        struct rxe_pkt_info *pkt = NULL;
        int ret = 0;
 
+       rxe_add_ref(qp);
+
        qp->resp.aeth_syndrome = AETH_ACK_UNLIMITED;
 
        if (!qp->valid) {
@@ -1400,5 +1402,6 @@ int rxe_responder(void *arg)
 exit:
        ret = -EAGAIN;
 done:
+       rxe_drop_ref(qp);
        return ret;
 }