]> git.openfabrics.org - ~shefty/librdmacm.git/commitdiff
rdma/verbs: Fix race polling for completions
authorSean Hefty <sean.hefty@intel.com>
Fri, 16 Sep 2011 19:06:40 +0000 (12:06 -0700)
committerSean Hefty <sean.hefty@intel.com>
Tue, 27 Sep 2011 18:17:12 +0000 (11:17 -0700)
To avoid hanging in rdma_get_send/recv_comp, we need to rearm
the CQ inside of the while loop.  If the CQ is armed,
the HCA will write an entry to the CQ, then generate a CQ
event.  However, a caller could poll the CQ, find the entry,
then attempt to rearm the CQ before the HCA generates the CQ
event.  In this case, the rearm call (ibv_req_notify_cq) will
act as a no-op, since the HCA hasn't finished generating the
event for the previous completion.  At this point, the event
will be queued.

A call to ibv_get_cq_event will find the event, but not
a CQ entry.  The CQ is now not armed, and a call to
ibv_get_cq_event will block waiting for an event that will
never occur.

Problem was found in an rdma_cm example test under development.
The test can ping-pong messages between two applications.

Signed-off-by: Sean Hefty <sean.hefty@intel.com>
include/rdma/rdma_verbs.h

index eca2c7a0c2416252065ddbccfa47becfdab4ca38..2b1a961870073876dd16c29c242d9d85ac95f9a4 100644 (file)
@@ -254,23 +254,27 @@ rdma_get_send_comp(struct rdma_cm_id *id, struct ibv_wc *wc)
        void *context;
        int ret;
 
-       ret = ibv_poll_cq(id->send_cq, 1, wc);
-       if (ret)
-               goto out;
+       do {
+               ret = ibv_poll_cq(id->send_cq, 1, wc);
+               if (ret)
+                       break;
 
-       ret = ibv_req_notify_cq(id->send_cq, 0);
-       if (ret)
-               return rdma_seterrno(ret);
+               ret = ibv_req_notify_cq(id->send_cq, 0);
+               if (ret)
+                       return rdma_seterrno(ret);
+
+               ret = ibv_poll_cq(id->send_cq, 1, wc);
+               if (ret)
+                       break;
 
-       while (!(ret = ibv_poll_cq(id->send_cq, 1, wc))) {
                ret = ibv_get_cq_event(id->send_cq_channel, &cq, &context);
                if (ret)
                        return rdma_seterrno(ret);
 
                assert(cq == id->send_cq && context == id);
                ibv_ack_cq_events(id->send_cq, 1);
-       }
-out:
+       } while (1);
+
        return (ret < 0) ? rdma_seterrno(ret) : ret;
 }
 
@@ -281,23 +285,27 @@ rdma_get_recv_comp(struct rdma_cm_id *id, struct ibv_wc *wc)
        void *context;
        int ret;
 
-       ret = ibv_poll_cq(id->recv_cq, 1, wc);
-       if (ret)
-               goto out;
+       do {
+               ret = ibv_poll_cq(id->recv_cq, 1, wc);
+               if (ret)
+                       break;
 
-       ret = ibv_req_notify_cq(id->recv_cq, 0);
-       if (ret)
-               return rdma_seterrno(ret);
+               ret = ibv_req_notify_cq(id->recv_cq, 0);
+               if (ret)
+                       return rdma_seterrno(ret);
+
+               ret = ibv_poll_cq(id->recv_cq, 1, wc);
+               if (ret)
+                       break;
 
-       while (!(ret = ibv_poll_cq(id->recv_cq, 1, wc))) {
                ret = ibv_get_cq_event(id->recv_cq_channel, &cq, &context);
                if (ret)
                        return rdma_seterrno(ret);
 
                assert(cq == id->recv_cq && context == id);
                ibv_ack_cq_events(id->recv_cq, 1);
-       }
-out:
+       } while (1);
+
        return (ret < 0) ? rdma_seterrno(ret) : ret;
 }