librdmacm: fix race in ucma_init()
authorshefty <shefty@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Wed, 26 Aug 2009 16:45:53 +0000 (16:45 +0000)
committershefty <shefty@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Wed, 26 Aug 2009 16:45:53 +0000 (16:45 +0000)
There's a potential race with ucma_init() and calls that check whether
the library is ready for use.  For example, in rdma_create_id, this
check is performed:

hr = cma_dev_cnt ? 0 : ucma_init();
if (hr) {
return hr;
}

Since the check for cma_dev_cnt is outside of any synchronization, if it
is non-zeroy, then the code will assume that initialization is complete.
However, ucma_init() can set cma_dev_cnt to non-zeroy before it has finished
executing.  The full impact of this race is unknown, but it can't be good.
In the worst case, the application may crash.

Fix this by ensuring that all initialization is complete before cma_dev_cnt
is incremented.  Note that ucma_init() provides synchronization to protect
against duplicate threads handling init.  The cma_dev_cnt check is used to
avoid synchronization on multiple calls into the library after initialization.

Signed-off-by: Sean Hefty <sean.hefty@intel.com>
git-svn-id: svn://openib.tc.cornell.edu/gen1/trunk@2383 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86

ulp/librdmacm/src/cma.cpp

index e732234..7d31c30 100644 (file)
@@ -91,63 +91,49 @@ struct cma_event {
 static struct cma_device *cma_dev_array;\r
 static int cma_dev_cnt;\r
 \r
 static struct cma_device *cma_dev_array;\r
 static int cma_dev_cnt;\r
 \r
-static void ucma_cleanup(void)\r
-{\r
-       if (cma_dev_cnt > 0) {\r
-               while (cma_dev_cnt > 0) {\r
-                       ibv_close_device(cma_dev_array[--cma_dev_cnt].verbs);\r
-               }\r
-               delete cma_dev_array;\r
-               cma_dev_cnt = 0;\r
-       }\r
-       if (windata.prov != NULL) {\r
-               ibvw_release_windata(&windata, IBVW_WINDATA_VERSION);\r
-               windata.prov = NULL;\r
-       }\r
-}\r
-\r
 static int ucma_init(void)\r
 {\r
        struct ibv_device **dev_list = NULL;\r
        struct cma_device *cma_dev;\r
        struct ibv_device_attr attr;\r
 static int ucma_init(void)\r
 {\r
        struct ibv_device **dev_list = NULL;\r
        struct cma_device *cma_dev;\r
        struct ibv_device_attr attr;\r
-       int i, ret;\r
+       int i, ret, dev_cnt;\r
 \r
        EnterCriticalSection(&lock);\r
 \r
        EnterCriticalSection(&lock);\r
-       if (cma_dev_cnt > 0) {\r
+       if (cma_dev_cnt) {\r
                goto out;\r
        }\r
 \r
        ret = ibvw_get_windata(&windata, IBVW_WINDATA_VERSION);\r
        if (ret) {\r
                goto out;\r
        }\r
 \r
        ret = ibvw_get_windata(&windata, IBVW_WINDATA_VERSION);\r
        if (ret) {\r
-               goto err;\r
+               goto err1;\r
        }\r
 \r
        }\r
 \r
-       dev_list = ibv_get_device_list(&cma_dev_cnt);\r
+       dev_list = ibv_get_device_list(&dev_cnt);\r
        if (dev_list == NULL) {\r
                ret = -1;\r
        if (dev_list == NULL) {\r
                ret = -1;\r
-               goto err;\r
+               goto err2;\r
        }\r
 \r
        }\r
 \r
-       cma_dev_array = new struct cma_device[cma_dev_cnt];\r
+       cma_dev_array = new struct cma_device[dev_cnt];\r
        if (cma_dev_array == NULL) {\r
                ret = -1;\r
        if (cma_dev_array == NULL) {\r
                ret = -1;\r
-               goto err;\r
+               goto err3;\r
        }\r
 \r
        }\r
 \r
-       for (i = 0; dev_list[i]; ++i) {\r
+       for (i = 0; dev_list[i];) {\r
                cma_dev = &cma_dev_array[i];\r
 \r
                cma_dev->guid = ibv_get_device_guid(dev_list[i]);\r
                cma_dev->verbs = ibv_open_device(dev_list[i]);\r
                if (cma_dev->verbs == NULL) {\r
                        ret = -1;\r
                cma_dev = &cma_dev_array[i];\r
 \r
                cma_dev->guid = ibv_get_device_guid(dev_list[i]);\r
                cma_dev->verbs = ibv_open_device(dev_list[i]);\r
                if (cma_dev->verbs == NULL) {\r
                        ret = -1;\r
-                       goto err;\r
+                       goto err4;\r
                }\r
 \r
                }\r
 \r
+               ++i;\r
                ret = ibv_query_device(cma_dev->verbs, &attr);\r
                if (ret) {\r
                ret = ibv_query_device(cma_dev->verbs, &attr);\r
                if (ret) {\r
-                       goto err;\r
+                       goto err4;\r
                }\r
 \r
                cma_dev->port_cnt = attr.phys_port_cnt;\r
                }\r
 \r
                cma_dev->port_cnt = attr.phys_port_cnt;\r
@@ -155,16 +141,22 @@ static int ucma_init(void)
                cma_dev->max_responder_resources = (uint8_t) attr.max_qp_rd_atom;\r
        }\r
        ibv_free_device_list(dev_list);\r
                cma_dev->max_responder_resources = (uint8_t) attr.max_qp_rd_atom;\r
        }\r
        ibv_free_device_list(dev_list);\r
+       cma_dev_cnt = dev_cnt;\r
 out:\r
        LeaveCriticalSection(&lock);\r
        return 0;\r
 \r
 out:\r
        LeaveCriticalSection(&lock);\r
        return 0;\r
 \r
-err:\r
-       ucma_cleanup();\r
-       LeaveCriticalSection(&lock);\r
-       if (dev_list) {\r
-               ibv_free_device_list(dev_list);\r
+err4:\r
+       while (i) {\r
+               ibv_close_device(cma_dev_array[--i].verbs);\r
        }\r
        }\r
+       delete cma_dev_array;\r
+err3:\r
+       ibv_free_device_list(dev_list);\r
+err2:\r
+       ibvw_release_windata(&windata, IBVW_WINDATA_VERSION);\r
+err1:\r
+       LeaveCriticalSection(&lock);\r
        return ret;\r
 }\r
 \r
        return ret;\r
 }\r
 \r