+++ /dev/null
-Bottom: eb069dacc3502ba7f9e575f462e80f48ec5b8fd4
-Top: a7464eef40af05ada562eed9d874eac97936fab7
-Author: Sean Hefty <sean.hefty@intel.com>
-Date: 2012-09-12 11:32:27 -0700
-
-libibverbs: Support older providers that do not support extensions
-
-In order to support providers that do not handle extensions, including
-providers built against an older version of ibverbs, add a compatibility
-layer. This allows most of the core ibverbs code to assume that
-extensions are always available. The compatibility layer is responsible
-for converting between the extended verbs and the current structure
-definitions.
-
-The compatibility layer allows applications to make use of extended
-structures, independent of the provider supporting them, and allows us
-to extend existing structures which are normally allocated by the
-provider: ibv_qp, ibv_srq, ibv_ah, ibv_mr, ibv_cq, ibv_pd, ibv_mw,
-and ibv_comp_channel. Existing applications are unaffected.
-
-The compatibility layer is similar to the 1.0 compat code. It allocates
-the extended structures, which then point to the ones allocated by the
-provider. For the most part, the compatibility code is invoked by
-directing the ibv_context ops into a compat function, which then redirects
-the call to the provider. This results in one extra level of indirection
-when running with a provider that does not support extensions.
-
-The exceptions to the indirection are opening and closing a device and
-handling asynchronous events.
-
-Signed-off-by: Sean Hefty <sean.hefty@intel.com>
-
-
----
-
-diff --git a/Makefile.am b/Makefile.am
-index cd00a65..1cfb008 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -11,7 +11,7 @@ libibverbs_version_script = @LIBIBVERBS_VERSION_SCRIPT@
-
- src_libibverbs_la_SOURCES = src/cmd.c src/compat-1_0.c src/device.c src/init.c \
- src/marshall.c src/memory.c src/sysfs.c src/verbs.c \
-- src/enum_strs.c
-+ src/enum_strs.c src/compat-ex.c
- src_libibverbs_la_LDFLAGS = -version-info 1 -export-dynamic \
- $(libibverbs_version_script)
- src_libibverbs_la_DEPENDENCIES = $(srcdir)/src/libibverbs.map
-diff --git a/include/infiniband/verbs.h b/include/infiniband/verbs.h
-index e67bf21..81e3f6d 100644
---- a/include/infiniband/verbs.h
-+++ b/include/infiniband/verbs.h
-@@ -308,9 +308,14 @@ enum ibv_access_flags {
- IBV_ACCESS_MW_BIND = (1<<4)
- };
-
-+enum ibv_pd_mask {
-+ IBV_PD_RESERVED = 1 << 0
-+};
-+
- struct ibv_pd {
- struct ibv_context *context;
- uint32_t handle;
-+ uint32_t comp_mask;
- };
-
- struct ibv_xrcd {
-@@ -324,6 +329,10 @@ enum ibv_rereg_mr_flags {
- IBV_REREG_MR_KEEP_VALID = (1 << 3)
- };
-
-+enum ibv_mr_mask {
-+ IBV_MR_RESERVED = 1 << 0
-+};
-+
- struct ibv_mr {
- struct ibv_context *context;
- struct ibv_pd *pd;
-@@ -332,6 +341,7 @@ struct ibv_mr {
- uint32_t handle;
- uint32_t lkey;
- uint32_t rkey;
-+ uint32_t comp_mask;
- };
-
- enum ibv_mw_type {
-@@ -339,10 +349,15 @@ enum ibv_mw_type {
- IBV_MW_TYPE_2 = 2
- };
-
-+enum ibv_mw_mask {
-+ IBV_MW_RESERVED = 1 << 0
-+};
-+
- struct ibv_mw {
- struct ibv_context *context;
- struct ibv_pd *pd;
- uint32_t rkey;
-+ uint32_t comp_mask;
- };
-
- struct ibv_global_route {
-@@ -595,6 +610,10 @@ struct ibv_mw_bind {
- int mw_access_flags;
- };
-
-+enum ibv_srq_mask {
-+ IBV_SRQ_RESERVED = 1 << 0
-+};
-+
- struct ibv_srq {
- struct ibv_context *context;
- void *srq_context;
-@@ -604,6 +623,12 @@ struct ibv_srq {
- pthread_mutex_t mutex;
- pthread_cond_t cond;
- uint32_t events_completed;
-+
-+ uint32_t comp_mask;
-+};
-+
-+enum ibv_qp_mask {
-+ IBV_QP_RESERVED = 1 << 0
- };
-
- struct ibv_qp {
-@@ -621,12 +646,24 @@ struct ibv_qp {
- pthread_mutex_t mutex;
- pthread_cond_t cond;
- uint32_t events_completed;
-+
-+ uint32_t comp_mask;
-+};
-+
-+enum ibv_comp_channel_mask {
-+ IBV_COMP_CHANNEL_RESERVED = 1 << 0
- };
-
- struct ibv_comp_channel {
- struct ibv_context *context;
- int fd;
- int refcnt;
-+
-+ uint32_t comp_mask;
-+};
-+
-+enum ibv_cq_mask {
-+ IBV_CQ_RESERVED = 1 << 0
- };
-
- struct ibv_cq {
-@@ -640,16 +677,25 @@ struct ibv_cq {
- pthread_cond_t cond;
- uint32_t comp_events_completed;
- uint32_t async_events_completed;
-+
-+ uint32_t comp_mask;
-+};
-+
-+enum ibv_ah_mask {
-+ IBV_AH_RESERVED = 1 << 0
- };
-
- struct ibv_ah {
- struct ibv_context *context;
- struct ibv_pd *pd;
- uint32_t handle;
-+
-+ uint32_t comp_mask;
- };
-
- struct ibv_device;
- struct ibv_context;
-+struct verbs_context;
-
- struct ibv_device_ops {
- struct ibv_context * (*alloc_context)(struct ibv_device *device, int cmd_fd);
-@@ -682,7 +728,7 @@ struct verbs_device {
- int (*init_context)(struct verbs_device *device,
- struct ibv_context *ctx, int cmd_fd);
- void (*uninit_context)(struct verbs_device *device,
-- struct ibv_context *ctx);
-+ struct ibv_context *ctx);
- /* future fields added here */
- };
-
-@@ -771,12 +817,8 @@ struct verbs_context {
- struct ibv_context context;/* Must be last field in the struct */
- };
-
--static inline struct verbs_context *verbs_get_ctx(
-- const struct ibv_context *ctx)
-+static inline struct verbs_context *verbs_get_ctx(const struct ibv_context *ctx)
- {
-- if (ctx->abi_compat != ((uint8_t *)NULL)-1)
-- return NULL;
--
- return container_of(ctx, struct verbs_context, context);
- }
-
-diff --git a/src/compat-ex.c b/src/compat-ex.c
-new file mode 100644
-index 0000000..d335d70
---- /dev/null
-+++ b/src/compat-ex.c
-@@ -0,0 +1,511 @@
-+/*
-+ * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
-+ * Copyright (c) 2012 Intel Corp., Inc. All rights reserved.
-+ *
-+ * This software is available to you under a choice of one of two
-+ * licenses. You may choose to be licensed under the terms of the GNU
-+ * General Public License (GPL) Version 2, available from the file
-+ * COPYING in the main directory of this source tree, or the
-+ * OpenIB.org BSD license below:
-+ *
-+ * Redistribution and use in source and binary forms, with or
-+ * without modification, are permitted provided that the following
-+ * conditions are met:
-+ *
-+ * - Redistributions of source code must retain the above
-+ * copyright notice, this list of conditions and the following
-+ * disclaimer.
-+ *
-+ * - Redistributions in binary form must reproduce the above
-+ * copyright notice, this list of conditions and the following
-+ * disclaimer in the documentation and/or other materials
-+ * provided with the distribution.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-+ * SOFTWARE.
-+ */
-+
-+#if HAVE_CONFIG_H
-+# include <config.h>
-+#endif /* HAVE_CONFIG_H */
-+
-+#include <string.h>
-+#include <stddef.h>
-+#include <stdlib.h>
-+#include <unistd.h>
-+#include <alloca.h>
-+
-+#include "ibverbs.h"
-+
-+struct _ibv_pd_ex {
-+ struct ibv_pd pd;
-+ struct ibv_pd *real_pd;
-+};
-+
-+struct _ibv_mr_ex {
-+ struct ibv_mr mr;
-+ struct ibv_mr *real_mr;
-+};
-+
-+struct _ibv_srq_ex {
-+ struct ibv_srq srq;
-+ struct ibv_srq *real_srq;
-+};
-+
-+struct _ibv_qp_ex {
-+ struct ibv_qp qp;
-+ struct ibv_qp *real_qp;
-+};
-+
-+struct _ibv_cq_ex {
-+ struct ibv_cq cq;
-+ struct ibv_cq *real_cq;
-+};
-+
-+struct _ibv_ah_ex {
-+ struct ibv_ah ah;
-+ struct ibv_ah *real_ah;
-+};
-+
-+struct ibv_context *_ibv_real_context(struct ibv_context *context)
-+{
-+ struct verbs_context_private *priv_ctx = ibv_private_context(context);
-+ return priv_ctx->real_context;
-+}
-+
-+struct ibv_srq *_ibv_real_srq(struct ibv_srq *srq)
-+{
-+ struct _ibv_srq_ex *srq_ex;
-+
-+ if (ibv_support_ex(srq->context))
-+ return srq;
-+
-+ srq_ex = container_of(srq, struct _ibv_srq_ex, srq);
-+ return srq_ex->real_srq;
-+}
-+
-+struct ibv_qp *_ibv_real_qp(struct ibv_qp *qp)
-+{
-+ struct _ibv_qp_ex *qp_ex;
-+
-+ if (ibv_support_ex(qp->context))
-+ return qp;
-+
-+ qp_ex = container_of(qp, struct _ibv_qp_ex, qp);
-+ return qp_ex->real_qp;
-+}
-+
-+struct ibv_cq *_ibv_real_cq(struct ibv_cq *cq)
-+{
-+ struct _ibv_cq_ex *cq_ex;
-+
-+ if (ibv_support_ex(cq->context))
-+ return cq;
-+
-+ cq_ex = container_of(cq, struct _ibv_cq_ex, cq);
-+ return cq_ex->real_cq;
-+}
-+
-+struct ibv_srq *_ibv_verbs_srq(struct ibv_srq *srq)
-+{
-+ return ibv_support_ex(srq->context) ? srq : (struct ibv_srq *) srq->srq_context;
-+}
-+
-+struct ibv_qp *_ibv_verbs_qp(struct ibv_qp *qp)
-+{
-+ return ibv_support_ex(qp->context) ? qp : (struct ibv_qp *) qp->qp_context;
-+}
-+
-+struct ibv_cq *_ibv_verbs_cq(struct ibv_cq *cq)
-+{
-+ return ibv_support_ex(cq->context) ? cq : (struct ibv_cq *) cq->cq_context;
-+}
-+
-+static int _ibv_query_device_ex(struct ibv_context *context,
-+ struct ibv_device_attr *device_attr)
-+{
-+ return ibv_query_device(_ibv_real_context(context), device_attr);
-+}
-+
-+static int _ibv_query_port_ex(struct ibv_context *context, uint8_t port_num,
-+ struct ibv_port_attr *port_attr)
-+{
-+ return ibv_query_port(_ibv_real_context(context), port_num, port_attr);
-+}
-+
-+static struct ibv_pd *_ibv_alloc_pd_ex(struct ibv_context *context)
-+{
-+ struct _ibv_pd_ex *pd_ex;
-+
-+ pd_ex = calloc(1, sizeof *pd_ex);
-+ if (!pd_ex)
-+ return NULL;
-+
-+ pd_ex->real_pd = ibv_alloc_pd(_ibv_real_context(context));
-+ if (!pd_ex->real_pd) {
-+ free(pd_ex);
-+ return NULL;
-+ }
-+
-+ return &pd_ex->pd;
-+}
-+
-+static int _ibv_dealloc_pd_ex(struct ibv_pd *pd)
-+{
-+ struct _ibv_pd_ex *pd_ex = container_of(pd, struct _ibv_pd_ex, pd);
-+ int ret;
-+
-+ ret = ibv_dealloc_pd(pd_ex->real_pd);
-+ if (ret)
-+ return ret;
-+
-+ free(pd_ex);
-+ return 0;
-+}
-+
-+static struct ibv_mr *_ibv_reg_mr_ex(struct ibv_pd *pd, void *addr, size_t length,
-+ int access)
-+{
-+ struct _ibv_pd_ex *pd_ex = container_of(pd, struct _ibv_pd_ex, pd);
-+ struct _ibv_mr_ex *mr_ex;
-+
-+ mr_ex = calloc(1, sizeof *mr_ex);
-+ if (!mr_ex)
-+ return NULL;
-+
-+ mr_ex->real_mr = ibv_reg_mr(pd_ex->real_pd, addr, length, access);
-+ if (!mr_ex->real_mr) {
-+ free(mr_ex);
-+ return NULL;
-+ }
-+
-+ mr_ex->mr.lkey = mr_ex->real_mr->lkey;
-+ mr_ex->mr.rkey = mr_ex->real_mr->rkey;
-+ return &mr_ex->mr;
-+}
-+
-+static int _ibv_dereg_mr_ex(struct ibv_mr *mr)
-+{
-+ struct _ibv_mr_ex *mr_ex = container_of(mr, struct _ibv_mr_ex, mr);
-+ int ret;
-+
-+ ret = ibv_dereg_mr(mr_ex->real_mr);
-+ if (ret)
-+ return ret;
-+
-+ free(mr_ex);
-+ return 0;
-+}
-+
-+/*
-+ * ibv_create_cq holds the channel mutex while calling the provider. We
-+ * cannot call ibv_create_cq recursively, so we need to call the provider
-+ * directly and duplicate initializing the ibv_cq.
-+ */
-+struct ibv_cq *_ibv_create_cq_ex(struct ibv_context *context, int cqe,
-+ struct ibv_comp_channel *channel,
-+ int comp_vector)
-+{
-+ struct ibv_context *real_context= _ibv_real_context(context);
-+ struct _ibv_cq_ex *cq_ex;
-+
-+ cq_ex = calloc(1, sizeof *cq_ex);
-+ if (!cq_ex)
-+ return NULL;
-+
-+ cq_ex->real_cq = real_context->ops.create_cq(real_context, cqe,
-+ channel, comp_vector);
-+ if (!cq_ex->real_cq) {
-+ free(cq_ex);
-+ return NULL;
-+ }
-+
-+ cq_ex->real_cq->context = real_context;
-+ cq_ex->real_cq->channel = channel;
-+ if (channel)
-+ ++channel->refcnt;
-+ cq_ex->real_cq->cq_context = cq_ex;
-+ cq_ex->real_cq->comp_events_completed = 0;
-+ cq_ex->real_cq->async_events_completed = 0;
-+ pthread_mutex_init(&cq_ex->real_cq->mutex, NULL);
-+ pthread_cond_init(&cq_ex->real_cq->cond, NULL);
-+
-+ cq_ex->cq.cqe = cq_ex->real_cq->cqe;
-+ return &cq_ex->cq;
-+}
-+
-+static int _ibv_poll_cq_ex(struct ibv_cq *cq, int num_entries, struct ibv_wc *wc)
-+{
-+ return ibv_poll_cq(_ibv_real_cq(cq), num_entries, wc);
-+}
-+
-+static int _ibv_req_notify_cq_ex(struct ibv_cq *cq, int solicited_only)
-+{
-+ return ibv_req_notify_cq(_ibv_real_cq(cq), solicited_only);
-+}
-+
-+static int _ibv_resize_cq_ex(struct ibv_cq *cq, int cqe)
-+{
-+ struct _ibv_cq_ex *cq_ex = container_of(cq, struct _ibv_cq_ex, cq);
-+ int ret;
-+
-+ ret = ibv_resize_cq(cq_ex->real_cq, cqe);
-+ if (ret)
-+ return ret;
-+
-+ cq_ex->cq.cqe = cq_ex->real_cq->cqe;
-+ return 0;
-+}
-+
-+/*
-+ * ibv_destroy_cq holds the mutex to any corresponding channel. Call the
-+ * provider directly.
-+ */
-+static int _ibv_destroy_cq_ex(struct ibv_cq *cq)
-+{
-+ struct _ibv_cq_ex *cq_ex = container_of(cq, struct _ibv_cq_ex, cq);
-+ int ret;
-+
-+ ret = cq_ex->real_cq->context->ops.destroy_cq(cq_ex->real_cq);
-+ if (ret)
-+ return ret;
-+
-+ if (cq_ex->cq.channel)
-+ --cq_ex->cq.channel->refcnt;
-+
-+ free(cq_ex);
-+ return 0;
-+}
-+
-+static struct ibv_srq *_ibv_create_srq_ex(struct ibv_pd *pd,
-+ struct ibv_srq_init_attr *srq_init_attr)
-+{
-+ struct _ibv_pd_ex *pd_ex = container_of(pd, struct _ibv_pd_ex, pd);
-+ struct _ibv_srq_ex *srq_ex;
-+
-+ srq_ex = calloc(1, sizeof *srq_ex);
-+ if (!srq_ex)
-+ return NULL;
-+
-+ srq_ex->real_srq = ibv_create_srq(pd_ex->real_pd, srq_init_attr);
-+ if (!srq_ex->real_srq) {
-+ free(srq_ex);
-+ return NULL;
-+ }
-+
-+ return &srq_ex->srq;
-+}
-+
-+static int _ibv_modify_srq_ex(struct ibv_srq *srq,
-+ struct ibv_srq_attr *srq_attr,
-+ int srq_attr_mask)
-+{
-+ return ibv_modify_srq(_ibv_real_srq(srq), srq_attr, srq_attr_mask);
-+}
-+
-+static int _ibv_query_srq_ex(struct ibv_srq *srq,
-+ struct ibv_srq_attr *srq_attr)
-+{
-+ return ibv_query_srq(_ibv_real_srq(srq), srq_attr);
-+}
-+
-+static int _ibv_destroy_srq_ex(struct ibv_srq *srq)
-+{
-+ struct _ibv_srq_ex *srq_ex = container_of(srq, struct _ibv_srq_ex, srq);
-+ int ret;
-+
-+ ret = ibv_destroy_srq(srq_ex->real_srq);
-+ if (ret)
-+ return ret;
-+
-+ free(srq_ex);
-+ return 0;
-+}
-+
-+static int _ibv_post_srq_recv_ex(struct ibv_srq *srq,
-+ struct ibv_recv_wr *recv_wr,
-+ struct ibv_recv_wr **bad_recv_wr)
-+{
-+ struct _ibv_srq_ex *srq_ex = container_of(srq, struct _ibv_srq_ex, srq);
-+ return ibv_post_srq_recv(srq_ex->real_srq, recv_wr, bad_recv_wr);
-+}
-+
-+static struct ibv_qp *_ibv_create_qp_ex(struct ibv_pd *pd, struct ibv_qp_init_attr *attr)
-+{
-+ struct _ibv_pd_ex *pd_ex = container_of(pd, struct _ibv_pd_ex, pd);
-+ struct _ibv_qp_ex *qp_ex;
-+ struct ibv_qp_init_attr real_attr;
-+
-+ qp_ex = calloc(1, sizeof *qp_ex);
-+ if (!qp_ex)
-+ return NULL;
-+
-+ real_attr.qp_context = qp_ex;
-+ real_attr.send_cq = attr->send_cq ? _ibv_real_cq(attr->send_cq) : NULL;
-+ real_attr.recv_cq = attr->recv_cq ? _ibv_real_cq(attr->recv_cq) : NULL;
-+ real_attr.srq = attr->srq ? _ibv_real_srq(attr->srq) : NULL;
-+ real_attr.cap = attr->cap;
-+ real_attr.qp_type = attr->qp_type;
-+ real_attr.sq_sig_all = attr->sq_sig_all;
-+
-+ qp_ex->real_qp = ibv_create_qp(pd_ex->real_pd, &real_attr);
-+ if (!qp_ex->real_qp) {
-+ free(qp_ex);
-+ return NULL;
-+ }
-+
-+ qp_ex->qp.qp_num = qp_ex->real_qp->qp_num;
-+ return &qp_ex->qp;
-+}
-+
-+static int _ibv_query_qp_ex(struct ibv_qp *qp, struct ibv_qp_attr *attr,
-+ int attr_mask, struct ibv_qp_init_attr *init_attr)
-+{
-+ struct _ibv_qp_ex *qp_ex = container_of(qp, struct _ibv_qp_ex, qp);
-+ int ret;
-+
-+ ret = ibv_query_qp(qp_ex->real_qp, attr, attr_mask, init_attr);
-+ if (ret)
-+ return ret;
-+
-+ init_attr->qp_context = qp_ex->qp.qp_context;
-+ init_attr->send_cq = qp_ex->qp.send_cq;
-+ init_attr->recv_cq = qp_ex->qp.recv_cq;
-+ init_attr->srq = qp_ex->qp.srq;
-+ return 0;
-+}
-+
-+static int _ibv_modify_qp_ex(struct ibv_qp *qp, struct ibv_qp_attr *attr,
-+ int attr_mask)
-+{
-+ return ibv_modify_qp(_ibv_real_qp(qp), attr, attr_mask);
-+}
-+
-+static int _ibv_destroy_qp_ex(struct ibv_qp *qp)
-+{
-+ struct _ibv_qp_ex *qp_ex = container_of(qp, struct _ibv_qp_ex, qp);
-+ int ret;
-+
-+ ret = ibv_destroy_qp(qp_ex->real_qp);
-+ if (ret)
-+ return ret;
-+
-+ free(qp_ex);
-+ return 0;
-+}
-+
-+static int _ibv_post_send_ex(struct ibv_qp *qp, struct ibv_send_wr *wr,
-+ struct ibv_send_wr **bad_wr)
-+{
-+ struct _ibv_qp_ex *qp_ex = container_of(qp, struct _ibv_qp_ex, qp);
-+ struct _ibv_ah_ex *ah_ex;
-+ struct ibv_send_wr real_wr, *cur_wr;
-+ int ret;
-+
-+ if (qp->qp_type != IBV_QPT_UD)
-+ return ibv_post_send(qp_ex->real_qp, wr, bad_wr);
-+
-+ for (cur_wr = wr, ret = 0; cur_wr && !ret; cur_wr = cur_wr->next) {
-+ real_wr = *cur_wr;
-+ real_wr.next = NULL;
-+ ah_ex = container_of(cur_wr->wr.ud.ah, struct _ibv_ah_ex, ah);
-+ real_wr.wr.ud.ah = ah_ex->real_ah;
-+ ret = ibv_post_send(qp_ex->real_qp, &real_wr, bad_wr);
-+ }
-+ *bad_wr = cur_wr;
-+ return ret;
-+}
-+
-+static int _ibv_post_recv_ex(struct ibv_qp *qp, struct ibv_recv_wr *wr,
-+ struct ibv_recv_wr **bad_wr)
-+{
-+ struct _ibv_qp_ex *qp_ex = container_of(qp, struct _ibv_qp_ex, qp);
-+ return ibv_post_recv(qp_ex->real_qp, wr, bad_wr);
-+}
-+
-+static struct ibv_ah *_ibv_create_ah_ex(struct ibv_pd *pd, struct ibv_ah_attr *attr)
-+{
-+ struct _ibv_pd_ex *pd_ex = container_of(pd, struct _ibv_pd_ex, pd);
-+ struct _ibv_ah_ex *ah_ex;
-+
-+ ah_ex = calloc(1, sizeof *ah_ex);
-+ if (!ah_ex)
-+ return NULL;
-+
-+ ah_ex->real_ah = ibv_create_ah(pd_ex->real_pd, attr);
-+ if (!ah_ex->real_ah) {
-+ free(ah_ex);
-+ return NULL;
-+ }
-+
-+ return &ah_ex->ah;
-+}
-+
-+static int _ibv_destroy_ah_ex(struct ibv_ah *ah)
-+{
-+ struct _ibv_ah_ex *ah_ex = container_of(ah, struct _ibv_ah_ex, ah);
-+ int ret;
-+
-+ ret = ibv_destroy_ah(ah_ex->real_ah);
-+ if (ret)
-+ return ret;
-+
-+ free(ah_ex);
-+ return 0;
-+}
-+
-+static int _ibv_attach_mcast_ex(struct ibv_qp *qp, const union ibv_gid *gid,
-+ uint16_t lid)
-+{
-+ return ibv_attach_mcast(_ibv_real_qp(qp), gid, lid);
-+}
-+
-+static int _ibv_detach_mcast_ex(struct ibv_qp *qp, const union ibv_gid *gid,
-+ uint16_t lid)
-+{
-+ return ibv_detach_mcast(_ibv_real_qp(qp), gid, lid);
-+}
-+
-+void _ibv_init_context(struct ibv_device *device,
-+ struct verbs_context_private *priv_ctx, int cmd_fd)
-+{
-+ struct ibv_context_ops *ops = &priv_ctx->context_ex.context.ops;
-+
-+ priv_ctx->real_context->device = device;
-+ priv_ctx->real_context->cmd_fd = cmd_fd;
-+ pthread_mutex_init(&priv_ctx->real_context->mutex, NULL);
-+ priv_ctx->real_context->abi_compat = NULL;
-+
-+ ops->query_device = _ibv_query_device_ex;
-+ ops->query_port = _ibv_query_port_ex;
-+ ops->alloc_pd = _ibv_alloc_pd_ex;
-+ ops->dealloc_pd = _ibv_dealloc_pd_ex;
-+ ops->reg_mr = _ibv_reg_mr_ex;
-+ ops->dereg_mr = _ibv_dereg_mr_ex;
-+ ops->create_cq = _ibv_create_cq_ex;
-+ ops->poll_cq = _ibv_poll_cq_ex;
-+ ops->req_notify_cq = _ibv_req_notify_cq_ex;
-+ ops->resize_cq = _ibv_resize_cq_ex;
-+ ops->destroy_cq = _ibv_destroy_cq_ex;
-+ ops->create_srq = _ibv_create_srq_ex;
-+ ops->modify_srq = _ibv_modify_srq_ex;
-+ ops->query_srq = _ibv_query_srq_ex;
-+ ops->destroy_srq = _ibv_destroy_srq_ex;
-+ ops->post_srq_recv = _ibv_post_srq_recv_ex;
-+ ops->create_qp = _ibv_create_qp_ex;
-+ ops->query_qp = _ibv_query_qp_ex;
-+ ops->modify_qp = _ibv_modify_qp_ex;
-+ ops->destroy_qp = _ibv_destroy_qp_ex;
-+ ops->post_send = _ibv_post_send_ex;
-+ ops->post_recv = _ibv_post_recv_ex;
-+ ops->create_ah = _ibv_create_ah_ex;
-+ ops->destroy_ah = _ibv_destroy_ah_ex;
-+ ops->attach_mcast = _ibv_attach_mcast_ex;
-+ ops->detach_mcast = _ibv_detach_mcast_ex;
-+}
-diff --git a/src/device.c b/src/device.c
-index 9e43138..e9699b6 100644
---- a/src/device.c
-+++ b/src/device.c
-@@ -127,7 +127,9 @@ struct ibv_context *__ibv_open_device(struct ibv_device *device)
- char *devpath;
- int cmd_fd;
- struct ibv_context *context;
-- struct verbs_context *context_ex;
-+ struct verbs_context_private *priv_ctx;
-+ struct verbs_device *vdev;
-+ size_t prov_ctx_size;
-
- if (asprintf(&devpath, "/dev/infiniband/%s", device->dev_name) < 0)
- return NULL;
-@@ -144,49 +146,44 @@ struct ibv_context *__ibv_open_device(struct ibv_device *device)
-
- context = device->ops.alloc_context(device, cmd_fd);
- if (!context)
-- goto err;
-- if (context == (struct ibv_context *)(((uint8_t *)NULL)-1)) {
-- /* New provider that supports verbs extension was detected */
-- struct verbs_device *verbs_device =
-- verbs_get_device(device);
-- int ret;
--
-- /* Library now allocates the context */
-- context_ex = calloc(1, sizeof(*context_ex) +
-- verbs_device->size_of_context);
--
-- if (!context_ex) {
-- errno = ENOMEM;
-- goto err;
-- }
-- context = &context_ex->context;
-- /* Init new verbs_context */
-- context_ex->context.abi_compat = ((uint8_t *)NULL)-1;
-- context_ex->sz = sizeof(*context_ex);
--
-- /* Call provider to initialize its calls first */
-- ret = verbs_device->init_context(verbs_device,
-- &context_ex->context, cmd_fd);
-- if (ret)
-- goto verbs_err;
-- /* initialize *all* library ops to either lib calls or
-- * directly to provider calls.
-- context_ex-> lib_new_func1= __verbs_new_func1;
-- context_ex-> lib_new_func2= __verbs_new_func2;
-- */
-+ goto err1;
-+
-+ if (context == IBV_EXTENDED_VERBS) {
-+ vdev = verbs_get_device(device);
-+ prov_ctx_size = vdev->size_of_context;
-+ } else {
-+ vdev = NULL;
-+ prov_ctx_size = 0;
- }
-
-- context->device = device;
-- context->cmd_fd = cmd_fd;
-- pthread_mutex_init(&context->mutex, NULL);
-+ priv_ctx = calloc(1, sizeof(*priv_ctx) + prov_ctx_size);
-+ if (!priv_ctx) {
-+ errno = ENOMEM;
-+ goto err1;
-+ }
-
-- return context;
-+ priv_ctx->context_ex.sz = sizeof(struct verbs_context);
-+ if (vdev) {
-+ if (vdev->init_context(vdev, &priv_ctx->context_ex.context, cmd_fd))
-+ goto err2;
-+
-+ priv_ctx->real_context = &priv_ctx->context_ex.context;
-+ priv_ctx->context_ex.context.abi_compat = IBV_EXTENDED_VERBS;
-+ } else {
-+ priv_ctx->real_context = context;
-+ priv_ctx->context_ex.context.abi_compat = NULL;
-+ _ibv_init_context(device, priv_ctx, cmd_fd);
-+ }
-
--verbs_err:
-- free(context_ex);
--err:
-- close(cmd_fd);
-+ priv_ctx->context_ex.context.device = device;
-+ priv_ctx->context_ex.context.cmd_fd = cmd_fd;
-+ pthread_mutex_init(&priv_ctx->context_ex.context.mutex, NULL);
-+ return &priv_ctx->context_ex.context;
-
-+err2:
-+ free(priv_ctx);
-+err1:
-+ close(cmd_fd);
- return NULL;
- }
- default_symver(__ibv_open_device, ibv_open_device);
-@@ -196,17 +193,15 @@ int __ibv_close_device(struct ibv_context *context)
- int async_fd = context->async_fd;
- int cmd_fd = context->cmd_fd;
- int cq_fd = -1;
-- struct verbs_context *context_ex;
--
-- context_ex = verbs_get_ctx(context);
-- if (context_ex) {
-- struct verbs_device *verbs_device =
-- verbs_get_device(context->device);
-- /* Provider supports verbs extension */
-- verbs_device->uninit_context(verbs_device, context);
-- free(context_ex);
-- } else
-- context->device->ops.free_context(context);
-+ struct verbs_context_private *priv_ctx = ibv_private_context(context);
-+
-+ if (ibv_support_ex(context)) {
-+ struct verbs_device *verbs_device = verbs_get_device(context->device);
-+ verbs_device->uninit_context(verbs_device, &priv_ctx->context_ex.context);
-+ } else {
-+ context->device->ops.free_context(priv_ctx->real_context);
-+ }
-+ free(priv_ctx);
-
- close(async_fd);
- close(cmd_fd);
-@@ -221,6 +216,7 @@ int __ibv_get_async_event(struct ibv_context *context,
- struct ibv_async_event *event)
- {
- struct ibv_kern_async_event ev;
-+ int cqe = 0, qpe = 0, srqe = 0;
-
- if (read(context->async_fd, &ev, sizeof ev) != sizeof ev)
- return -1;
-@@ -230,6 +226,7 @@ int __ibv_get_async_event(struct ibv_context *context,
- switch (event->event_type) {
- case IBV_EVENT_CQ_ERR:
- event->element.cq = (void *) (uintptr_t) ev.element;
-+ cqe = 1;
- break;
-
- case IBV_EVENT_QP_FATAL:
-@@ -241,11 +238,13 @@ int __ibv_get_async_event(struct ibv_context *context,
- case IBV_EVENT_PATH_MIG_ERR:
- case IBV_EVENT_QP_LAST_WQE_REACHED:
- event->element.qp = (void *) (uintptr_t) ev.element;
-+ qpe = 1;
- break;
-
- case IBV_EVENT_SRQ_ERR:
- case IBV_EVENT_SRQ_LIMIT_REACHED:
- event->element.srq = (void *) (uintptr_t) ev.element;
-+ srqe = 1;
- break;
-
- default:
-@@ -256,6 +255,13 @@ int __ibv_get_async_event(struct ibv_context *context,
- if (context->ops.async_event)
- context->ops.async_event(event);
-
-+ if (cqe)
-+ event->element.cq = _ibv_verbs_cq(event->element.cq);
-+ else if (qpe)
-+ event->element.qp = _ibv_verbs_qp(event->element.qp);
-+ else if (srqe)
-+ event->element.srq = _ibv_verbs_srq(event->element.srq);
-+
- return 0;
- }
- default_symver(__ibv_get_async_event, ibv_get_async_event);
-@@ -265,7 +271,7 @@ void __ibv_ack_async_event(struct ibv_async_event *event)
- switch (event->event_type) {
- case IBV_EVENT_CQ_ERR:
- {
-- struct ibv_cq *cq = event->element.cq;
-+ struct ibv_cq *cq = _ibv_real_cq(event->element.cq);
-
- pthread_mutex_lock(&cq->mutex);
- ++cq->async_events_completed;
-@@ -284,7 +290,7 @@ void __ibv_ack_async_event(struct ibv_async_event *event)
- case IBV_EVENT_PATH_MIG_ERR:
- case IBV_EVENT_QP_LAST_WQE_REACHED:
- {
-- struct ibv_qp *qp = event->element.qp;
-+ struct ibv_qp *qp = _ibv_real_qp(event->element.qp);
-
- pthread_mutex_lock(&qp->mutex);
- ++qp->events_completed;
-@@ -297,7 +303,7 @@ void __ibv_ack_async_event(struct ibv_async_event *event)
- case IBV_EVENT_SRQ_ERR:
- case IBV_EVENT_SRQ_LIMIT_REACHED:
- {
-- struct ibv_srq *srq = event->element.srq;
-+ struct ibv_srq *srq = _ibv_real_srq(event->element.srq);
-
- pthread_mutex_lock(&srq->mutex);
- ++srq->events_completed;
-diff --git a/src/ibverbs.h b/src/ibverbs.h
-index fa6cd41..33049d4 100644
---- a/src/ibverbs.h
-+++ b/src/ibverbs.h
-@@ -102,4 +102,33 @@ HIDDEN int ibverbs_init(struct ibv_device ***list);
- (cmd)->response = (uintptr_t) (out); \
- } while (0)
-
-+struct verbs_context_private {
-+ struct ibv_context *real_context;
-+ /* place internal data before verbs_context */
-+ struct verbs_context context_ex;
-+};
-+
-+#define IBV_EXTENDED_VERBS (((void *) NULL) - 1)
-+
-+static inline int ibv_support_ex(struct ibv_context *context)
-+{
-+ return context->abi_compat == IBV_EXTENDED_VERBS;
-+}
-+
-+static inline struct verbs_context_private *
-+ibv_private_context(struct ibv_context *context)
-+{
-+ return container_of(verbs_get_ctx(context),
-+ struct verbs_context_private, context_ex);
-+}
-+
-+void _ibv_init_context(struct ibv_device *device,
-+ struct verbs_context_private *priv_ctx, int cmd_fd);
-+struct ibv_srq *_ibv_real_srq(struct ibv_srq *srq);
-+struct ibv_qp *_ibv_real_qp(struct ibv_qp *qp);
-+struct ibv_cq *_ibv_real_cq(struct ibv_cq *cq);
-+struct ibv_srq *_ibv_verbs_srq(struct ibv_srq *srq);
-+struct ibv_qp *_ibv_verbs_qp(struct ibv_qp *qp);
-+struct ibv_cq *_ibv_verbs_cq(struct ibv_cq *cq);
-+
- #endif /* IB_VERBS_H */
-diff --git a/src/verbs.c b/src/verbs.c
-index b5938f2..7973afc 100644
---- a/src/verbs.c
-+++ b/src/verbs.c
-@@ -334,18 +334,21 @@ int __ibv_get_cq_event(struct ibv_comp_channel *channel,
- if (read(channel->fd, &ev, sizeof ev) != sizeof ev)
- return -1;
-
-- *cq = (struct ibv_cq *) (uintptr_t) ev.cq_handle;
-- *cq_context = (*cq)->cq_context;
--
-+ *cq = (struct ibv_cq *) (uintptr_t) ev.cq_handle;
- if ((*cq)->context->ops.cq_event)
- (*cq)->context->ops.cq_event(*cq);
-
-+ if (!verbs_get_ctx((*cq)->context))
-+ *cq = (struct ibv_cq *) (*cq)->cq_context;
-+ *cq_context = (*cq)->cq_context;
-+
- return 0;
- }
- default_symver(__ibv_get_cq_event, ibv_get_cq_event);
-
- void __ibv_ack_cq_events(struct ibv_cq *cq, unsigned int nevents)
- {
-+ cq = _ibv_real_cq(cq);
- pthread_mutex_lock(&cq->mutex);
- cq->comp_events_completed += nevents;
- pthread_cond_signal(&cq->cond);