--- /dev/null
+Bottom: ff097d1ced43527502d645f75ecff80782d96d2d
+Top: 15914285befe61b6f050f9b8c56512b8ec98cbfe
+Author: Sean Hefty <sean.hefty@intel.com>
+Date: 2012-09-12 16:34:59 -0700
+
+Refresh of compat-ex
+
+---
+
+diff --git a/src/compat-ex.c b/src/compat-ex.c
+index 254747c..d822f73 100644
+--- a/src/compat-ex.c
++++ b/src/compat-ex.c
+@@ -43,773 +43,356 @@
+
+ #include "ibverbs.h"
+
+-struct ibv_pd_ex {
++struct _ibv_pd_ex {
+ struct ibv_pd pd;
+ struct ibv_pd *real_pd;
+ };
+
+-struct ibv_mr_ex {
++struct _ibv_mr_ex {
+ struct ibv_mr mr;
+ struct ibv_mr *real_mr;
+ };
+
+-struct ibv_mw_ex {
+- struct ibv_mw mw;
+- struct ibv_mw *real_mw;
+-};
+-
+-struct ibv_srq_ex {
++struct _ibv_srq_ex {
+ struct ibv_srq srq;
+ struct ibv_srq *real_srq;
+ };
+
+-struct ibv_qp_ex {
++struct _ibv_qp_ex {
+ struct ibv_qp qp;
+ struct ibv_qp *real_qp;
+ };
+
+-struct ibv_cq_ex {
++struct _ibv_cq_ex {
+ struct ibv_cq cq;
+ struct ibv_cq *real_cq;
+ };
+
+-struct ibv_ah_ex {
++struct _ibv_ah_ex {
+ struct ibv_ah ah;
+ struct ibv_ah *real_ah;
+ };
+
+-struct ibv_context_ops_1_0 {
+- int (*query_device)(struct ibv_context *context,
+- struct ibv_device_attr *device_attr);
+- int (*query_port)(struct ibv_context *context, uint8_t port_num,
+- struct ibv_port_attr *port_attr);
+- struct ibv_pd * (*alloc_pd)(struct ibv_context *context);
+- int (*dealloc_pd)(struct ibv_pd *pd);
+- struct ibv_mr * (*reg_mr)(struct ibv_pd *pd, void *addr, size_t length,
+- int access);
+- int (*dereg_mr)(struct ibv_mr *mr);
+- struct ibv_cq * (*create_cq)(struct ibv_context *context, int cqe,
+- struct ibv_comp_channel *channel,
+- int comp_vector);
+- int (*poll_cq)(struct ibv_cq_1_0 *cq, int num_entries,
+- struct ibv_wc *wc);
+- int (*req_notify_cq)(struct ibv_cq_1_0 *cq,
+- int solicited_only);
+- void (*cq_event)(struct ibv_cq *cq);
+- int (*resize_cq)(struct ibv_cq *cq, int cqe);
+- int (*destroy_cq)(struct ibv_cq *cq);
+- struct ibv_srq * (*create_srq)(struct ibv_pd *pd,
+- struct ibv_srq_init_attr *srq_init_attr);
+- int (*modify_srq)(struct ibv_srq *srq,
+- struct ibv_srq_attr *srq_attr,
+- int srq_attr_mask);
+- int (*query_srq)(struct ibv_srq *srq,
+- struct ibv_srq_attr *srq_attr);
+- int (*destroy_srq)(struct ibv_srq *srq);
+- int (*post_srq_recv)(struct ibv_srq_1_0 *srq,
+- struct ibv_recv_wr_1_0 *recv_wr,
+- struct ibv_recv_wr_1_0 **bad_recv_wr);
+- struct ibv_qp * (*create_qp)(struct ibv_pd *pd, struct ibv_qp_init_attr *attr);
+- int (*query_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+- int attr_mask,
+- struct ibv_qp_init_attr *init_attr);
+- int (*modify_qp)(struct ibv_qp *qp, struct ibv_qp_attr *attr,
+- int attr_mask);
+- int (*destroy_qp)(struct ibv_qp *qp);
+- int (*post_send)(struct ibv_qp_1_0 *qp,
+- struct ibv_send_wr_1_0 *wr,
+- struct ibv_send_wr_1_0 **bad_wr);
+- int (*post_recv)(struct ibv_qp_1_0 *qp,
+- struct ibv_recv_wr_1_0 *wr,
+- struct ibv_recv_wr_1_0 **bad_wr);
+- struct ibv_ah * (*create_ah)(struct ibv_pd *pd, struct ibv_ah_attr *attr);
+- int (*destroy_ah)(struct ibv_ah *ah);
+- int (*attach_mcast)(struct ibv_qp *qp, union ibv_gid *gid,
+- uint16_t lid);
+- int (*detach_mcast)(struct ibv_qp *qp, union ibv_gid *gid,
+- uint16_t lid);
+-};
+-
+-struct ibv_context_1_0 {
+- struct ibv_device_1_0 *device;
+- struct ibv_context_ops_1_0 ops;
+- int cmd_fd;
+- int async_fd;
+- int num_comp_vectors;
+-
+- struct ibv_context *real_context; /* was abi_compat member */
++struct _ibv_context_ex {
++ struct ibv_context context;
++ struct ibv_context *real_context;
+ };
+
+-struct ibv_device_1_0 **__ibv_get_device_list_1_0(int *num)
+-{
+- struct ibv_device **real_list;
+- struct ibv_device_1_0 **l;
+- int i, n;
+-
+- real_list = ibv_get_device_list(&n);
+- if (!real_list)
+- return NULL;
+-
+- l = calloc(n + 2, sizeof (struct ibv_device_1_0 *));
+- if (!l)
+- goto free_device_list;
+-
+- l[0] = (void *) real_list;
+-
+- for (i = 0; i < n; ++i) {
+- l[i + 1] = calloc(1, sizeof (struct ibv_device_1_0));
+- if (!l[i + 1])
+- goto fail;
+- l[i + 1]->real_device = real_list[i];
+- }
+-
+- if (num)
+- *num = n;
+-
+- return l + 1;
+-
+-fail:
+- for (i = 1; i <= n; ++i)
+- if (l[i])
+- free(l[i]);
+- free(l);
+-
+-free_device_list:
+- ibv_free_device_list(real_list);
+- return NULL;
+-}
+-symver(__ibv_get_device_list_1_0, ibv_get_device_list, IBVERBS_1.0);
+-
+-void __ibv_free_device_list_1_0(struct ibv_device_1_0 **list)
+-{
+- struct ibv_device_1_0 **l = list;
+-
+- while (*l) {
+- free(*l);
+- ++l;
+- }
+-
+- ibv_free_device_list((void *) list[-1]);
+- free(list - 1);
+-}
+-symver(__ibv_free_device_list_1_0, ibv_free_device_list, IBVERBS_1.0);
+-
+-const char *__ibv_get_device_name_1_0(struct ibv_device_1_0 *device)
+-{
+- return ibv_get_device_name(device->real_device);
+-}
+-symver(__ibv_get_device_name_1_0, ibv_get_device_name, IBVERBS_1.0);
+-
+-uint64_t __ibv_get_device_guid_1_0(struct ibv_device_1_0 *device)
+-{
+- return ibv_get_device_guid(device->real_device);
+-}
+-symver(__ibv_get_device_guid_1_0, ibv_get_device_guid, IBVERBS_1.0);
+-
+-static int poll_cq_wrapper_1_0(struct ibv_cq_1_0 *cq, int num_entries,
+- struct ibv_wc *wc)
++static int _ibv_query_device_ex(struct ibv_context *context,
++ struct ibv_device_attr *device_attr)
+ {
+- return cq->context->real_context->ops.poll_cq(cq->real_cq, num_entries, wc);
++ struct _ibv_context_ex *context_ex;
++ context_ex = container_of(context, struct _ibv_context_ex, context);
++ return ibv_query_device(context_ex->real_context, device_attr);
+ }
+
+-static int req_notify_cq_wrapper_1_0(struct ibv_cq_1_0 *cq, int sol_only)
++static int _ibv_query_port_ex(struct ibv_context *context, uint8_t port_num,
++ struct ibv_port_attr *port_attr)
+ {
+- return cq->context->real_context->ops.req_notify_cq(cq->real_cq, sol_only);
++ struct _ibv_context_ex *context_ex;
++ context_ex = container_of(context, struct _ibv_context_ex, context);
++ return ibv_query_port(context_ex->real_context, port_num, port_attr);
+ }
+
+-static int post_srq_recv_wrapper_1_0(struct ibv_srq_1_0 *srq, struct ibv_recv_wr_1_0 *wr,
+- struct ibv_recv_wr_1_0 **bad_wr)
++static struct ibv_pd *_ibv_alloc_pd_ex(struct ibv_context *context)
+ {
+- struct ibv_recv_wr_1_0 *w;
+- struct ibv_recv_wr *real_wr, *head_wr = NULL, *tail_wr = NULL, *real_bad_wr;
+- int ret;
+-
+- for (w = wr; w; w = w->next) {
+- real_wr = alloca(sizeof *real_wr);
+- real_wr->wr_id = w->wr_id;
+- real_wr->sg_list = w->sg_list;
+- real_wr->num_sge = w->num_sge;
+- real_wr->next = NULL;
+- if (tail_wr)
+- tail_wr->next = real_wr;
+- else
+- head_wr = real_wr;
+-
+- tail_wr = real_wr;
+- }
+-
+- ret = srq->context->real_context->ops.post_srq_recv(srq->real_srq, head_wr,
+- &real_bad_wr);
+-
+- if (ret) {
+- for (real_wr = head_wr, w = wr;
+- real_wr;
+- real_wr = real_wr->next, w = w->next)
+- if (real_wr == real_bad_wr) {
+- *bad_wr = w;
+- break;
+- }
+- }
+-
+- return ret;
+-}
+-
+-static int post_send_wrapper_1_0(struct ibv_qp_1_0 *qp, struct ibv_send_wr_1_0 *wr,
+- struct ibv_send_wr_1_0 **bad_wr)
+-{
+- struct ibv_send_wr_1_0 *w;
+- struct ibv_send_wr *real_wr, *head_wr = NULL, *tail_wr = NULL, *real_bad_wr;
+- int is_ud = qp->qp_type == IBV_QPT_UD;
+- int ret;
++ struct _ibv_context_ex *context_ex;
++ struct _ibv_pd_ex *pd_ex;
+
+- for (w = wr; w; w = w->next) {
+- real_wr = alloca(sizeof *real_wr);
+- real_wr->wr_id = w->wr_id;
+- real_wr->next = NULL;
+-
+- memcpy(&real_wr->sg_list, &w->sg_list,
+- sizeof *w - offsetof(struct ibv_send_wr, sg_list));
+-
+- if (is_ud)
+- real_wr->wr.ud.ah = w->wr.ud.ah->real_ah;
+-
+- if (tail_wr)
+- tail_wr->next = real_wr;
+- else
+- head_wr = real_wr;
+-
+- tail_wr = real_wr;
+- }
++ context_ex = container_of(context, struct _ibv_context_ex, context);
++ pd_ex = calloc(1, sizeof *pd_ex);
++ if (!pd_ex)
++ return NULL;
+
+- ret = qp->context->real_context->ops.post_send(qp->real_qp, head_wr,
+- &real_bad_wr);
+-
+- if (ret) {
+- for (real_wr = head_wr, w = wr;
+- real_wr;
+- real_wr = real_wr->next, w = w->next)
+- if (real_wr == real_bad_wr) {
+- *bad_wr = w;
+- break;
+- }
++ pd_ex->real_pd = ibv_alloc_pd(context_ex->real_context);
++ if (!pd_ex->real_pd) {
++ free(pd_ex);
++ return NULL;
+ }
+
+- return ret;
++ return &pd_ex->pd;
+ }
+
+-static int post_recv_wrapper_1_0(struct ibv_qp_1_0 *qp, struct ibv_recv_wr_1_0 *wr,
+- struct ibv_recv_wr_1_0 **bad_wr)
++static int _ibv_dealloc_pd_ex(struct ibv_pd *pd)
+ {
+- struct ibv_recv_wr_1_0 *w;
+- struct ibv_recv_wr *real_wr, *head_wr = NULL, *tail_wr = NULL, *real_bad_wr;
++ struct _ibv_pd_ex *pd_ex = container_of(pd, struct _ibv_pd_ex, pd);
+ int ret;
+
+- for (w = wr; w; w = w->next) {
+- real_wr = alloca(sizeof *real_wr);
+- real_wr->wr_id = w->wr_id;
+- real_wr->sg_list = w->sg_list;
+- real_wr->num_sge = w->num_sge;
+- real_wr->next = NULL;
+- if (tail_wr)
+- tail_wr->next = real_wr;
+- else
+- head_wr = real_wr;
+-
+- tail_wr = real_wr;
+- }
+-
+- ret = qp->context->real_context->ops.post_recv(qp->real_qp, head_wr,
+- &real_bad_wr);
+-
+- if (ret) {
+- for (real_wr = head_wr, w = wr;
+- real_wr;
+- real_wr = real_wr->next, w = w->next)
+- if (real_wr == real_bad_wr) {
+- *bad_wr = w;
+- break;
+- }
+- }
++ ret = ibv_dealloc_pd(pd_ex->real_pd);
++ if (ret)
++ return ret;
+
+- return ret;
++ free(pd_ex);
++ return 0;
+ }
+
+-struct ibv_context_1_0 *__ibv_open_device_1_0(struct ibv_device_1_0 *device)
++static struct ibv_mr *_ibv_reg_mr_ex(struct ibv_pd *pd, void *addr, size_t length,
++ int access)
+ {
+- struct ibv_context *real_ctx;
+- struct ibv_context_1_0 *ctx;
++ struct _ibv_pd_ex *pd_ex = container_of(pd, struct _ibv_pd_ex, pd);
++ struct _ibv_mr_ex *mr_ex;
+
+- ctx = malloc(sizeof *ctx);
+- if (!ctx)
++ mr_ex = calloc(1, sizeof *mr_ex);
++ if (!mr_ex)
+ return NULL;
+
+- real_ctx = ibv_open_device(device->real_device);
+- if (!real_ctx) {
+- free(ctx);
++ mr_ex->real_mr = ibv_reg_mr(pd_ex->real_pd, addr, length, access);
++ if (!mr_ex->real_mr) {
++ free(mr_ex);
+ return NULL;
+ }
+
+- ctx->device = device;
+- ctx->real_context = real_ctx;
+-
+- ctx->ops.poll_cq = poll_cq_wrapper_1_0;
+- ctx->ops.req_notify_cq = req_notify_cq_wrapper_1_0;
+- ctx->ops.post_send = post_send_wrapper_1_0;
+- ctx->ops.post_recv = post_recv_wrapper_1_0;
+- ctx->ops.post_srq_recv = post_srq_recv_wrapper_1_0;
+-
+- return ctx;
++ mr_ex->mr.lkey = mr_ex->real_mr->lkey;
++ mr_ex->mr.rkey = mr_ex->real_mr->rkey;
++ return &mr_ex->mr;
+ }
+-symver(__ibv_open_device_1_0, ibv_open_device, IBVERBS_1.0);
+
+-int __ibv_close_device_1_0(struct ibv_context_1_0 *context)
++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_close_device(context->real_context);
++ ret = ibv_dereg_mr(mr_ex->real_mr);
+ if (ret)
+ return ret;
+
+- free(context);
++ free(mr_ex);
+ return 0;
+ }
+-symver(__ibv_close_device_1_0, ibv_close_device, IBVERBS_1.0);
+
+-int __ibv_get_async_event_1_0(struct ibv_context_1_0 *context,
+- struct ibv_async_event *event)
++/*
++ * 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)
+ {
+- int ret;
+-
+- ret = ibv_get_async_event(context->real_context, event);
+- if (ret)
+- return ret;
+-
+- switch (event->event_type) {
+- case IBV_EVENT_CQ_ERR:
+- event->element.cq = event->element.cq->cq_context;
+- break;
+-
+- case IBV_EVENT_QP_FATAL:
+- case IBV_EVENT_QP_REQ_ERR:
+- case IBV_EVENT_QP_ACCESS_ERR:
+- case IBV_EVENT_COMM_EST:
+- case IBV_EVENT_SQ_DRAINED:
+- case IBV_EVENT_PATH_MIG:
+- case IBV_EVENT_PATH_MIG_ERR:
+- case IBV_EVENT_QP_LAST_WQE_REACHED:
+- event->element.qp = event->element.qp->qp_context;
+- break;
+-
+- case IBV_EVENT_SRQ_ERR:
+- case IBV_EVENT_SRQ_LIMIT_REACHED:
+- event->element.srq = event->element.srq->srq_context;
+- break;
+-
+- default:
+- break;
+- }
++ struct _ibv_context_ex *context_ex;
++ struct _ibv_cq_ex *cq_ex;
+
+- return ret;
+-}
+-symver(__ibv_get_async_event_1_0, ibv_get_async_event, IBVERBS_1.0);
++ context_ex = container_of(context, struct _ibv_context_ex, context);
++ cq_ex = calloc(1, sizeof *cq_ex);
++ if (!cq_ex)
++ return NULL;
+
+-void __ibv_ack_async_event_1_0(struct ibv_async_event *event)
+-{
+- struct ibv_async_event real_event = *event;
+-
+- switch (event->event_type) {
+- case IBV_EVENT_CQ_ERR:
+- real_event.element.cq =
+- ((struct ibv_cq_1_0 *) event->element.cq)->real_cq;
+- break;
+-
+- case IBV_EVENT_QP_FATAL:
+- case IBV_EVENT_QP_REQ_ERR:
+- case IBV_EVENT_QP_ACCESS_ERR:
+- case IBV_EVENT_COMM_EST:
+- case IBV_EVENT_SQ_DRAINED:
+- case IBV_EVENT_PATH_MIG:
+- case IBV_EVENT_PATH_MIG_ERR:
+- case IBV_EVENT_QP_LAST_WQE_REACHED:
+- real_event.element.qp =
+- ((struct ibv_qp_1_0 *) event->element.qp)->real_qp;
+- break;
+-
+- case IBV_EVENT_SRQ_ERR:
+- case IBV_EVENT_SRQ_LIMIT_REACHED:
+- real_event.element.srq =
+- ((struct ibv_srq_1_0 *) event->element.srq)->real_srq;
+- break;
+-
+- default:
+- break;
++ cq_ex->real_cq = context_ex->real_context->ops.create_cq(context_ex->real_context,
++ cqe, channel, comp_vector);
++ if (!cq_ex->real_cq) {
++ free(cq_ex);
++ return NULL;
+ }
+
+- ibv_ack_async_event(&real_event);
+-}
+-symver(__ibv_ack_async_event_1_0, ibv_ack_async_event, IBVERBS_1.0);
+-
+-int __ibv_query_device_1_0(struct ibv_context_1_0 *context,
+- struct ibv_device_attr *device_attr)
+-{
+- return ibv_query_device(context->real_context, device_attr);
+-}
+-symver(__ibv_query_device_1_0, ibv_query_device, IBVERBS_1.0);
++ cq_ex->real_cq->context = context_ex->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);
+
+-int __ibv_query_port_1_0(struct ibv_context_1_0 *context, uint8_t port_num,
+- struct ibv_port_attr *port_attr)
+-{
+- return ibv_query_port(context->real_context, port_num, port_attr);
++ cq_ex->cq.cqe = cq_ex->real_cq->cqe;
++ return &cq_ex->cq;
+ }
+-symver(__ibv_query_port_1_0, ibv_query_port, IBVERBS_1.0);
+
+-int __ibv_query_gid_1_0(struct ibv_context_1_0 *context, uint8_t port_num,
+- int index, union ibv_gid *gid)
++static int _ibv_poll_cq_ex(struct ibv_cq *cq, int num_entries, struct ibv_wc *wc)
+ {
+- return ibv_query_gid(context->real_context, port_num, index, gid);
++ struct _ibv_cq_ex *cq_ex = container_of(cq, struct _ibv_cq_ex, cq);
++ return ibv_poll_cq(cq_ex->real_cq, num_entries, wc);
+ }
+-symver(__ibv_query_gid_1_0, ibv_query_gid, IBVERBS_1.0);
+
+-int __ibv_query_pkey_1_0(struct ibv_context_1_0 *context, uint8_t port_num,
+- int index, uint16_t *pkey)
++static int _ibv_req_notify_cq_ex(struct ibv_cq *cq, int solicited_only)
+ {
+- return ibv_query_pkey(context->real_context, port_num, index, pkey);
++ struct _ibv_cq_ex *cq_ex = container_of(cq, struct _ibv_cq_ex, cq);
++ return ibv_req_notify_cq(cq_ex->real_cq, solicited_only);
+ }
+-symver(__ibv_query_pkey_1_0, ibv_query_pkey, IBVERBS_1.0);
+
+-struct ibv_pd_1_0 *__ibv_alloc_pd_1_0(struct ibv_context_1_0 *context)
++static void _ibv_cq_event_ex(struct ibv_cq *cq)
+ {
+- struct ibv_pd *real_pd;
+- struct ibv_pd_1_0 *pd;
+-
+- pd = malloc(sizeof *pd);
+- if (!pd)
+- return NULL;
++ struct _ibv_cq_ex *cq_ex = container_of(cq, struct _ibv_cq_ex, cq);
++ struct _ibv_context_ex *context_ex;
+
+- real_pd = ibv_alloc_pd(context->real_context);
+- if (!real_pd) {
+- free(pd);
+- return NULL;
+- }
+-
+- pd->context = context;
+- pd->real_pd = real_pd;
+-
+- return pd;
++ context_ex = container_of(cq->context, struct _ibv_context_ex, context);
++ return context_ex->real_context->ops.cq_event(cq_ex->real_cq);
+ }
+-symver(__ibv_alloc_pd_1_0, ibv_alloc_pd, IBVERBS_1.0);
+
+-int __ibv_dealloc_pd_1_0(struct ibv_pd_1_0 *pd)
++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_dealloc_pd(pd->real_pd);
++ ret = ibv_resize_cq(cq_ex->real_cq, cqe);
+ if (ret)
+ return ret;
+
+- free(pd);
++ cq_ex->cq.cqe = cq_ex->real_cq->cqe;
+ return 0;
+ }
+-symver(__ibv_dealloc_pd_1_0, ibv_dealloc_pd, IBVERBS_1.0);
+-
+-struct ibv_mr_1_0 *__ibv_reg_mr_1_0(struct ibv_pd_1_0 *pd, void *addr,
+- size_t length, int access)
+-{
+- struct ibv_mr *real_mr;
+- struct ibv_mr_1_0 *mr;
+-
+- mr = malloc(sizeof *mr);
+- if (!mr)
+- return NULL;
+-
+- real_mr = ibv_reg_mr(pd->real_pd, addr, length, access);
+- if (!real_mr) {
+- free(mr);
+- return NULL;
+- }
+-
+- mr->context = pd->context;
+- mr->pd = pd;
+- mr->lkey = real_mr->lkey;
+- mr->rkey = real_mr->rkey;
+- mr->real_mr = real_mr;
+-
+- return mr;
+-}
+-symver(__ibv_reg_mr_1_0, ibv_reg_mr, IBVERBS_1.0);
+
+-int __ibv_dereg_mr_1_0(struct ibv_mr_1_0 *mr)
++/*
++ * 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 = ibv_dereg_mr(mr->real_mr);
++ ret = cq_ex->real_cq->context->ops.destroy_cq(cq_ex->real_cq);
+ if (ret)
+ return ret;
+
+- free(mr);
++ if (cq_ex->cq.channel)
++ --cq_ex->cq.channel->refcnt;
++
++ free(cq_ex);
+ return 0;
+ }
+-symver(__ibv_dereg_mr_1_0, ibv_dereg_mr, IBVERBS_1.0);
+
+-struct ibv_cq_1_0 *__ibv_create_cq_1_0(struct ibv_context_1_0 *context, int cqe,
+- void *cq_context,
+- struct ibv_comp_channel *channel,
+- int comp_vector)
++static struct ibv_srq *_ibv_create_srq_ex(struct ibv_pd *pd,
++ struct ibv_srq_init_attr *srq_init_attr)
+ {
+- struct ibv_cq *real_cq;
+- struct ibv_cq_1_0 *cq;
++ struct _ibv_pd_ex *pd_ex = container_of(pd, struct _ibv_pd_ex, pd);
++ struct _ibv_srq_ex *srq_ex;
+
+- cq = malloc(sizeof *cq);
+- if (!cq)
++ srq_ex = calloc(1, sizeof *srq_ex);
++ if (!srq_ex)
+ return NULL;
+
+- real_cq = ibv_create_cq(context->real_context, cqe, cq_context,
+- channel, comp_vector);
+- if (!real_cq) {
+- free(cq);
++ srq_ex->real_srq = ibv_create_srq(pd_ex->real_pd, srq_init_attr);
++ if (!srq_ex->real_srq) {
++ free(srq_ex);
+ return NULL;
+ }
+
+- cq->context = context;
+- cq->cq_context = cq_context;
+- cq->cqe = cqe;
+- cq->real_cq = real_cq;
+-
+- real_cq->cq_context = cq;
+-
+- return cq;
++ return &srq_ex->srq;
+ }
+-symver(__ibv_create_cq_1_0, ibv_create_cq, IBVERBS_1.0);
+
+-int __ibv_resize_cq_1_0(struct ibv_cq_1_0 *cq, int cqe)
++static int _ibv_modify_srq_ex(struct ibv_srq *srq,
++ struct ibv_srq_attr *srq_attr,
++ int srq_attr_mask)
+ {
+- return ibv_resize_cq(cq->real_cq, cqe);
++ struct _ibv_srq_ex *srq_ex;
++ srq_ex = container_of(srq, struct _ibv_srq_ex, srq);
++
+ }
+-symver(__ibv_resize_cq_1_0, ibv_resize_cq, IBVERBS_1.0);
+
+-int __ibv_destroy_cq_1_0(struct ibv_cq_1_0 *cq)
++static int _ibv_query_srq_ex(struct ibv_srq *srq,
++ struct ibv_srq_attr *srq_attr)
+ {
+- int ret;
+-
+- ret = ibv_destroy_cq(cq->real_cq);
+- if (ret)
+- return ret;
++ struct _ibv_srq_ex *srq_ex;
++ srq_ex = container_of(srq, struct _ibv_srq_ex, srq);
+
+- free(cq);
+- return 0;
+ }
+-symver(__ibv_destroy_cq_1_0, ibv_destroy_cq, IBVERBS_1.0);
+
+-int __ibv_get_cq_event_1_0(struct ibv_comp_channel *channel,
+- struct ibv_cq_1_0 **cq, void **cq_context)
++static int _ibv_destroy_srq_ex(struct ibv_srq *srq)
+ {
+- struct ibv_cq *real_cq;
+- void *cq_ptr;
+- int ret;
+-
+- ret = ibv_get_cq_event(channel, &real_cq, &cq_ptr);
+- if (ret)
+- return ret;
+-
+- *cq = cq_ptr;
+- *cq_context = (*cq)->cq_context;
++ struct _ibv_srq_ex *srq_ex;
++ srq_ex = container_of(srq, struct _ibv_srq_ex, srq);
+
+- return 0;
+ }
+-symver(__ibv_get_cq_event_1_0, ibv_get_cq_event, IBVERBS_1.0);
+
+-void __ibv_ack_cq_events_1_0(struct ibv_cq_1_0 *cq, unsigned int nevents)
++static int _ibv_post_srq_recv_ex(struct ibv_srq *srq,
++ struct ibv_recv_wr *recv_wr,
++ struct ibv_recv_wr **bad_recv_wr)
+ {
+- ibv_ack_cq_events(cq->real_cq, nevents);
++ struct _ibv_srq_ex *srq_ex;
++ srq_ex = container_of(srq, struct _ibv_srq_ex, srq);
++
+ }
+-symver(__ibv_ack_cq_events_1_0, ibv_ack_cq_events, IBVERBS_1.0);
+
+-struct ibv_srq_1_0 *__ibv_create_srq_1_0(struct ibv_pd_1_0 *pd,
+- struct ibv_srq_init_attr *srq_init_attr)
++static struct ibv_qp *_ibv_create_qp_ex(struct ibv_pd *pd, struct ibv_qp_init_attr *attr)
+ {
+- struct ibv_srq *real_srq;
+- struct ibv_srq_1_0 *srq;
+-
+- srq = malloc(sizeof *srq);
+- if (!srq)
+- return NULL;
+-
+- real_srq = ibv_create_srq(pd->real_pd, srq_init_attr);
+- if (!real_srq) {
+- free(srq);
+- return NULL;
+- }
+-
+- srq->context = pd->context;
+- srq->srq_context = srq_init_attr->srq_context;
+- srq->pd = pd;
+- srq->real_srq = real_srq;
+-
+- real_srq->srq_context = srq;
++ struct _ibv_pd_ex *pd_ex;
++ pd_ex = container_of(pd, struct _ibv_pd_ex, pd);
+
+- return srq;
+ }
+-symver(__ibv_create_srq_1_0, ibv_create_srq, IBVERBS_1.0);
+
+-int __ibv_modify_srq_1_0(struct ibv_srq_1_0 *srq,
+- struct ibv_srq_attr *srq_attr,
+- int srq_attr_mask)
++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)
+ {
+- return ibv_modify_srq(srq->real_srq, srq_attr, srq_attr_mask);
+-}
+-symver(__ibv_modify_srq_1_0, ibv_modify_srq, IBVERBS_1.0);
++ struct _ibv_qp_ex *qp_ex;
++ qp_ex = container_of(qp, struct _ibv_qp_ex, qp);
+
+-int __ibv_query_srq_1_0(struct ibv_srq_1_0 *srq, struct ibv_srq_attr *srq_attr)
+-{
+- return ibv_query_srq(srq->real_srq, srq_attr);
+ }
+-symver(__ibv_query_srq_1_0, ibv_query_srq, IBVERBS_1.0);
+
+-int __ibv_destroy_srq_1_0(struct ibv_srq_1_0 *srq)
++static int _ibv_modify_qp_ex(struct ibv_qp *qp, struct ibv_qp_attr *attr,
++ int attr_mask)
+ {
+- int ret;
++ struct _ibv_qp_ex *qp_ex;
++ qp_ex = container_of(qp, struct _ibv_qp_ex, qp);
+
+- ret = ibv_destroy_srq(srq->real_srq);
+- if (ret)
+- return ret;
+-
+- free(srq);
+- return 0;
+ }
+-symver(__ibv_destroy_srq_1_0, ibv_destroy_srq, IBVERBS_1.0);
+
+-struct ibv_qp_1_0 *__ibv_create_qp_1_0(struct ibv_pd_1_0 *pd,
+- struct ibv_qp_init_attr_1_0 *qp_init_attr)
++static int _ibv_destroy_qp_ex(struct ibv_qp *qp)
+ {
+- struct ibv_qp *real_qp;
+- struct ibv_qp_1_0 *qp;
+- struct ibv_qp_init_attr real_init_attr;
+-
+- qp = malloc(sizeof *qp);
+- if (!qp)
+- return NULL;
+-
+- real_init_attr.qp_context = qp_init_attr->qp_context;
+- real_init_attr.send_cq = qp_init_attr->send_cq->real_cq;
+- real_init_attr.recv_cq = qp_init_attr->recv_cq->real_cq;
+- real_init_attr.srq = qp_init_attr->srq ?
+- qp_init_attr->srq->real_srq : NULL;
+- real_init_attr.cap = qp_init_attr->cap;
+- real_init_attr.qp_type = qp_init_attr->qp_type;
+- real_init_attr.sq_sig_all = qp_init_attr->sq_sig_all;
+-
+- real_qp = ibv_create_qp(pd->real_pd, &real_init_attr);
+- if (!real_qp) {
+- free(qp);
+- return NULL;
+- }
+-
+- qp->context = pd->context;
+- qp->qp_context = qp_init_attr->qp_context;
+- qp->pd = pd;
+- qp->send_cq = qp_init_attr->send_cq;
+- qp->recv_cq = qp_init_attr->recv_cq;
+- qp->srq = qp_init_attr->srq;
+- qp->qp_type = qp_init_attr->qp_type;
+- qp->qp_num = real_qp->qp_num;
+- qp->real_qp = real_qp;
+-
+- qp_init_attr->cap = real_init_attr.cap;
++ struct _ibv_qp_ex *qp_ex;
++ qp_ex = container_of(qp, struct _ibv_qp_ex, qp);
+
+- real_qp->qp_context = qp;
+-
+- return qp;
+ }
+-symver(__ibv_create_qp_1_0, ibv_create_qp, IBVERBS_1.0);
+
+-int __ibv_query_qp_1_0(struct ibv_qp_1_0 *qp, struct ibv_qp_attr *attr,
+- int attr_mask,
+- struct ibv_qp_init_attr_1_0 *init_attr)
++static int _ibv_post_send_ex(struct ibv_qp *qp, struct ibv_send_wr *wr,
++ struct ibv_send_wr **bad_wr)
+ {
+- struct ibv_qp_init_attr real_init_attr;
+- int ret;
++ struct _ibv_qp_ex *qp_ex;
++ qp_ex = container_of(qp, struct _ibv_qp_ex, qp);
+
+- ret = ibv_query_qp(qp->real_qp, attr, attr_mask, &real_init_attr);
+- if (ret)
+- return ret;
++}
+
+- init_attr->qp_context = qp->qp_context;
+- init_attr->send_cq = real_init_attr.send_cq->cq_context;
+- init_attr->recv_cq = real_init_attr.recv_cq->cq_context;
+- init_attr->srq = real_init_attr.srq->srq_context;
+- init_attr->qp_type = real_init_attr.qp_type;
+- init_attr->cap = real_init_attr.cap;
+- init_attr->sq_sig_all = real_init_attr.sq_sig_all;
++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;
++ qp_ex = container_of(qp, struct _ibv_qp_ex, qp);
+
+- return 0;
+ }
+-symver(__ibv_query_qp_1_0, ibv_query_qp, IBVERBS_1.0);
+
+-int __ibv_modify_qp_1_0(struct ibv_qp_1_0 *qp, struct ibv_qp_attr *attr,
+- int attr_mask)
++static struct ibv_ah *_ibv_create_ah_ex(struct ibv_pd *pd, struct ibv_ah_attr *attr)
+ {
+- return ibv_modify_qp(qp->real_qp, attr, attr_mask);
++ struct _ibv_pd_ex *pd_ex;
++ struct _ibv_ah_ex *ah_ex;
++ pd_ex = container_of(pd, struct _ibv_pd_ex, pd);
++
+ }
+-symver(__ibv_modify_qp_1_0, ibv_modify_qp, IBVERBS_1.0);
+
+-int __ibv_destroy_qp_1_0(struct ibv_qp_1_0 *qp)
++static int _ibv_destroy_ah_ex(struct ibv_ah *ah)
+ {
+- int ret;
+-
+- ret = ibv_destroy_qp(qp->real_qp);
+- if (ret)
+- return ret;
++ struct _ibv_ah_ex *ah_ex;
++ ah_ex = container_of(ah, struct _ibv_ah_ex, ah);
+
+- free(qp);
+- return 0;
+ }
+-symver(__ibv_destroy_qp_1_0, ibv_destroy_qp, IBVERBS_1.0);
+
+-struct ibv_ah_1_0 *__ibv_create_ah_1_0(struct ibv_pd_1_0 *pd,
+- struct ibv_ah_attr *attr)
++static int _ibv_attach_mcast_ex(struct ibv_qp *qp, const union ibv_gid *gid,
++ uint16_t lid)
+ {
+- struct ibv_ah *real_ah;
+- struct ibv_ah_1_0 *ah;
++ struct _ibv_qp_ex *qp_ex;
++ qp_ex = container_of(qp, struct _ibv_qp_ex, qp);
+
+- ah = malloc(sizeof *ah);
+- if (!ah)
+- return NULL;
+-
+- real_ah = ibv_create_ah(pd->real_pd, attr);
+- if (!real_ah) {
+- free(ah);
+- return NULL;
+- }
++}
+
+- ah->context = pd->context;
+- ah->pd = pd;
+- ah->real_ah = real_ah;
++static int _ibv_detach_mcast_ex(struct ibv_qp *qp, const union ibv_gid *gid,
++ uint16_t lid)
++{
++ struct _ibv_qp_ex *qp_ex;
++ qp_ex = container_of(qp, struct _ibv_qp_ex, qp);
+
+- return ah;
+ }
+-symver(__ibv_create_ah_1_0, ibv_create_ah, IBVERBS_1.0);
+
+-int __ibv_destroy_ah_1_0(struct ibv_ah_1_0 *ah)
++static void _ibv_async_event_ex(struct ibv_async_event *event)
+ {
+- int ret;
+-
+- ret = ibv_destroy_ah(ah->real_ah);
+- if (ret)
+- return ret;
+
+- free(ah);
+- return 0;
+ }
+-symver(__ibv_destroy_ah_1_0, ibv_destroy_ah, IBVERBS_1.0);
+
+-int __ibv_attach_mcast_1_0(struct ibv_qp_1_0 *qp, union ibv_gid *gid, uint16_t lid)
++struct ibv_context *_ibv_open_device_ex(struct ibv_device *device)
+ {
+- return ibv_attach_mcast(qp->real_qp, gid, lid);
++
+ }
+-symver(__ibv_attach_mcast_1_0, ibv_attach_mcast, IBVERBS_1.0);
+
+-int __ibv_detach_mcast_1_0(struct ibv_qp_1_0 *qp, union ibv_gid *gid, uint16_t lid)
++int _ibv_close_device_ex(struct ibv_context *context)
+ {
+- return ibv_detach_mcast(qp->real_qp, gid, lid);
++
+ }
+-symver(__ibv_detach_mcast_1_0, ibv_detach_mcast, IBVERBS_1.0);