kfree(mc);
 }
 
-static void cma_detach_from_dev(struct rdma_id_private *id_priv)
+static void cma_release_dev(struct rdma_id_private *id_priv)
 {
+       mutex_lock(&lock);
        list_del(&id_priv->list);
        cma_deref_dev(id_priv->cma_dev);
        id_priv->cma_dev = NULL;
+       mutex_unlock(&lock);
 }
 
 static int cma_set_qkey(struct rdma_id_private *id_priv)
        enum rdma_link_layer dev_ll = dev_addr->dev_type == ARPHRD_INFINIBAND ?
                IB_LINK_LAYER_INFINIBAND : IB_LINK_LAYER_ETHERNET;
 
+       mutex_lock(&lock);
        iboe_addr_get_sgid(dev_addr, &iboe_gid);
        memcpy(&gid, dev_addr->src_dev_addr +
               rdma_addr_gid_offset(dev_addr), sizeof gid);
        if (!ret)
                cma_attach_to_dev(id_priv, cma_dev);
 
+       mutex_unlock(&lock);
        return ret;
 }
 
        state = cma_exch(id_priv, CMA_DESTROYING);
        cma_cancel_operation(id_priv, state);
 
-       mutex_lock(&lock);
+       /*
+        * Wait for any active callback to finish.  New callbacks will find
+        * the id_priv state set to destroying and abort.
+        */
+       mutex_lock(&id_priv->handler_mutex);
+       mutex_unlock(&id_priv->handler_mutex);
+
        if (id_priv->cma_dev) {
-               mutex_unlock(&lock);
                switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
                case RDMA_TRANSPORT_IB:
                        if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
                        break;
                }
                cma_leave_mc_groups(id_priv);
-               mutex_lock(&lock);
-               cma_detach_from_dev(id_priv);
+               cma_release_dev(id_priv);
        }
-       mutex_unlock(&lock);
 
        cma_release_port(id_priv);
        cma_deref_id(id_priv);
        }
 
        mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING);
-       mutex_lock(&lock);
        ret = cma_acquire_dev(conn_id);
-       mutex_unlock(&lock);
        if (ret)
                goto release_conn_id;
 
                goto out;
        }
 
-       mutex_lock(&lock);
        ret = cma_acquire_dev(conn_id);
-       mutex_unlock(&lock);
        if (ret) {
                mutex_unlock(&conn_id->handler_mutex);
                rdma_destroy_id(new_cm_id);
 
        memset(&event, 0, sizeof event);
        mutex_lock(&id_priv->handler_mutex);
-
-       /*
-        * Grab mutex to block rdma_destroy_id() from removing the device while
-        * we're trying to acquire it.
-        */
-       mutex_lock(&lock);
-       if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED)) {
-               mutex_unlock(&lock);
+       if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED))
                goto out;
-       }
 
        if (!status && !id_priv->cma_dev)
                status = cma_acquire_dev(id_priv);
-       mutex_unlock(&lock);
 
        if (status) {
                if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ADDR_BOUND))
                if (ret)
                        goto err1;
 
-               mutex_lock(&lock);
                ret = cma_acquire_dev(id_priv);
-               mutex_unlock(&lock);
                if (ret)
                        goto err1;
        }
 
        return 0;
 err2:
-       if (id_priv->cma_dev) {
-               mutex_lock(&lock);
-               cma_detach_from_dev(id_priv);
-               mutex_unlock(&lock);
-       }
+       if (id_priv->cma_dev)
+               cma_release_dev(id_priv);
 err1:
        cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_IDLE);
        return ret;