diff mbox

[1/8] verbs: Always allocate a verbs_context

Message ID 20180108212632.5183-2-jgg@ziepe.ca (mailing list archive)
State Accepted
Delegated to: Leon Romanovsky
Headers show

Commit Message

Jason Gunthorpe Jan. 8, 2018, 9:26 p.m. UTC
From: Jason Gunthorpe <jgg@mellanox.com>

Now that everything is in one tree we can revise the legacy init_context
path to always allocate a verbs_context by swapping the ibv_context
for a verbs_context in all of the provider's wrapper struct.

To keep the provider diffs minimal this single patch does several things
at once:

- Introduce the verbs_init_and_alloc_context() macro.
  This allocates, zeros and initializes the verbs_context for each driver.
  Notably this new macro correctly sets errno as required upon failure.

- Remove boilerplate from all drivers, calloc, malloc, memset, cmd_fd and
  device assignment

- Along with the verbs_init scheme necessarily comes the verbs_uninit
  scheme which lowers the uninit call into the provder not the common
  code. This allows us to properly uninit on the init error path.

Together this follows the fairly successful pattern we see in the kernel
for driver init to a subsystem.

Also this changes ibv_cmd_get_context to accept a verbs_context since
the majority of callers are now providing that, this keeps the diff
smaller.

This makes the entire flow more consistent and will let us eliminate the
init_context flow.

Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
---
 CMakeLists.txt                     |   2 +-
 debian/libibverbs1.symbols         |   2 +-
 libibverbs/cmd.c                   |  12 +--
 libibverbs/device.c                | 206 +++++++++++++++++++++++--------------
 libibverbs/driver.h                |  23 ++++-
 libibverbs/libibverbs.map.in       |   2 +
 providers/bnxt_re/main.c           |   5 +-
 providers/cxgb3/iwch.c             |  30 +++---
 providers/cxgb3/iwch.h             |   4 +-
 providers/cxgb4/dev.c              |  29 +++---
 providers/cxgb4/libcxgb4.h         |   4 +-
 providers/hfi1verbs/hfiverbs.c     |  36 ++++---
 providers/hfi1verbs/hfiverbs.h     |   4 +-
 providers/hns/hns_roce_u.c         |  53 +++++-----
 providers/hns/hns_roce_u.h         |   4 +-
 providers/hns/hns_roce_u_verbs.c   |   6 +-
 providers/i40iw/i40iw_umain.c      |  16 +--
 providers/i40iw/i40iw_umain.h      |   4 +-
 providers/ipathverbs/ipathverbs.c  |  36 ++++---
 providers/ipathverbs/ipathverbs.h  |   4 +-
 providers/mlx4/mlx4.c              |   8 +-
 providers/mlx5/mlx5.c              |   8 +-
 providers/mthca/mthca.c            |  48 +++++----
 providers/mthca/mthca.h            |   4 +-
 providers/nes/nes_umain.c          |  19 ++--
 providers/nes/nes_umain.h          |   4 +-
 providers/ocrdma/ocrdma_main.c     |  14 ++-
 providers/ocrdma/ocrdma_main.h     |   4 +-
 providers/qedr/qelr.h              |   4 +-
 providers/qedr/qelr_main.c         |  14 +--
 providers/qedr/qelr_verbs.c        |   2 +-
 providers/rxe/rxe.c                |  13 ++-
 providers/rxe/rxe.h                |   4 +-
 providers/vmw_pvrdma/pvrdma.h      |   4 +-
 providers/vmw_pvrdma/pvrdma_main.c |  14 +--
 35 files changed, 359 insertions(+), 287 deletions(-)

Comments

Devesh Sharma Jan. 10, 2018, 5:46 a.m. UTC | #1
On Tue, Jan 9, 2018 at 2:56 AM, Jason Gunthorpe <jgg@ziepe.ca> wrote:
> From: Jason Gunthorpe <jgg@mellanox.com>
>
> Now that everything is in one tree we can revise the legacy init_context
> path to always allocate a verbs_context by swapping the ibv_context
> for a verbs_context in all of the provider's wrapper struct.
>
> To keep the provider diffs minimal this single patch does several things
> at once:
>
> - Introduce the verbs_init_and_alloc_context() macro.
>   This allocates, zeros and initializes the verbs_context for each driver.
>   Notably this new macro correctly sets errno as required upon failure.
>
> - Remove boilerplate from all drivers, calloc, malloc, memset, cmd_fd and
>   device assignment
>
> - Along with the verbs_init scheme necessarily comes the verbs_uninit
>   scheme which lowers the uninit call into the provder not the common
>   code. This allows us to properly uninit on the init error path.
>
> Together this follows the fairly successful pattern we see in the kernel
> for driver init to a subsystem.
>
> Also this changes ibv_cmd_get_context to accept a verbs_context since
> the majority of callers are now providing that, this keeps the diff
> smaller.
>
> This makes the entire flow more consistent and will let us eliminate the
> init_context flow.
>
> Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
> ---
>  CMakeLists.txt                     |   2 +-
>  debian/libibverbs1.symbols         |   2 +-
>  libibverbs/cmd.c                   |  12 +--
>  libibverbs/device.c                | 206 +++++++++++++++++++++++--------------
>  libibverbs/driver.h                |  23 ++++-
>  libibverbs/libibverbs.map.in       |   2 +
>  providers/bnxt_re/main.c           |   5 +-
>  providers/cxgb3/iwch.c             |  30 +++---
>  providers/cxgb3/iwch.h             |   4 +-
>  providers/cxgb4/dev.c              |  29 +++---
>  providers/cxgb4/libcxgb4.h         |   4 +-
>  providers/hfi1verbs/hfiverbs.c     |  36 ++++---
>  providers/hfi1verbs/hfiverbs.h     |   4 +-
>  providers/hns/hns_roce_u.c         |  53 +++++-----
>  providers/hns/hns_roce_u.h         |   4 +-
>  providers/hns/hns_roce_u_verbs.c   |   6 +-
>  providers/i40iw/i40iw_umain.c      |  16 +--
>  providers/i40iw/i40iw_umain.h      |   4 +-
>  providers/ipathverbs/ipathverbs.c  |  36 ++++---
>  providers/ipathverbs/ipathverbs.h  |   4 +-
>  providers/mlx4/mlx4.c              |   8 +-
>  providers/mlx5/mlx5.c              |   8 +-
>  providers/mthca/mthca.c            |  48 +++++----
>  providers/mthca/mthca.h            |   4 +-
>  providers/nes/nes_umain.c          |  19 ++--
>  providers/nes/nes_umain.h          |   4 +-
>  providers/ocrdma/ocrdma_main.c     |  14 ++-
>  providers/ocrdma/ocrdma_main.h     |   4 +-
>  providers/qedr/qelr.h              |   4 +-
>  providers/qedr/qelr_main.c         |  14 +--
>  providers/qedr/qelr_verbs.c        |   2 +-
>  providers/rxe/rxe.c                |  13 ++-
>  providers/rxe/rxe.h                |   4 +-
>  providers/vmw_pvrdma/pvrdma.h      |   4 +-
>  providers/vmw_pvrdma/pvrdma_main.c |  14 +--
>  35 files changed, 359 insertions(+), 287 deletions(-)
>
> diff --git a/CMakeLists.txt b/CMakeLists.txt
> index b1467317b68561..e8f4a948ad9610 100644
> --- a/CMakeLists.txt
> +++ b/CMakeLists.txt
> @@ -52,7 +52,7 @@ set(PACKAGE_VERSION "17.0")
>  # When this is changed the values in these files need changing too:
>  #   debian/libibverbs1.symbols
>  #   libibverbs/libibverbs.map
> -set(IBVERBS_PABI_VERSION "16")
> +set(IBVERBS_PABI_VERSION "17")
>  set(IBVERBS_PROVIDER_SUFFIX "-rdmav${IBVERBS_PABI_VERSION}.so")
>
>  #-------------------------
> diff --git a/debian/libibverbs1.symbols b/debian/libibverbs1.symbols
> index 2678fa6e98acf7..7c7659e434bc63 100644
> --- a/debian/libibverbs1.symbols
> +++ b/debian/libibverbs1.symbols
> @@ -1,7 +1,7 @@
>  libibverbs.so.1 libibverbs1 #MINVER#
>   IBVERBS_1.0@IBVERBS_1.0 1.1.6
>   IBVERBS_1.1@IBVERBS_1.1 1.1.6
> - (symver)IBVERBS_PRIVATE_16 16
> + (symver)IBVERBS_PRIVATE_17 17
>   ibv_ack_async_event@IBVERBS_1.0 1.1.6
>   ibv_ack_async_event@IBVERBS_1.1 1.1.6
>   ibv_ack_cq_events@IBVERBS_1.0 1.1.6
> diff --git a/libibverbs/cmd.c b/libibverbs/cmd.c
> index b957550ed6fbdb..bcec94f5b0ce72 100644
> --- a/libibverbs/cmd.c
> +++ b/libibverbs/cmd.c
> @@ -44,22 +44,22 @@
>  #include "ibverbs.h"
>  #include <ccan/minmax.h>
>
> -int ibv_cmd_get_context(struct ibv_context *context, struct ibv_get_context *cmd,
> -                       size_t cmd_size, struct ibv_get_context_resp *resp,
> -                       size_t resp_size)
> +int ibv_cmd_get_context(struct verbs_context *context_ex,
> +                       struct ibv_get_context *cmd, size_t cmd_size,
> +                       struct ibv_get_context_resp *resp, size_t resp_size)
>  {
>         if (abi_ver < IB_USER_VERBS_MIN_ABI_VERSION)
>                 return ENOSYS;
>
>         IBV_INIT_CMD_RESP(cmd, cmd_size, GET_CONTEXT, resp, resp_size);
>
> -       if (write(context->cmd_fd, cmd, cmd_size) != cmd_size)
> +       if (write(context_ex->context.cmd_fd, cmd, cmd_size) != cmd_size)
>                 return errno;
>
>         (void) VALGRIND_MAKE_MEM_DEFINED(resp, resp_size);
>
> -       context->async_fd         = resp->async_fd;
> -       context->num_comp_vectors = resp->num_comp_vectors;
> +       context_ex->context.async_fd = resp->async_fd;
> +       context_ex->context.num_comp_vectors = resp->num_comp_vectors;
>
>         return 0;
>  }
> diff --git a/libibverbs/device.c b/libibverbs/device.c
> index 4fb759c6474ad7..e42e37bd0a1f8d 100644
> --- a/libibverbs/device.c
> +++ b/libibverbs/device.c
> @@ -162,7 +162,8 @@ static struct ibv_cq_ex *
>  __lib_ibv_create_cq_ex(struct ibv_context *context,
>                        struct ibv_cq_init_attr_ex *cq_attr)
>  {
> -       struct verbs_context *vctx = verbs_get_ctx(context);
> +       struct verbs_context *vctx =
> +               container_of(context, struct verbs_context, context);
>         struct ibv_cq_ex *cq;
>
>         if (cq_attr->wc_flags & ~IBV_CREATE_CQ_SUP_WC_FLAGS) {
> @@ -179,14 +180,115 @@ __lib_ibv_create_cq_ex(struct ibv_context *context,
>         return cq;
>  }
>
> +/*
> + * Ownership of cmd_fd is transferred into this function, and it will either
> + * be released during the matching call to verbs_uninit_contxt or during the
> + * failure path of this function.
> + */
> +int verbs_init_context(struct verbs_context *context_ex,
> +                      struct ibv_device *device, int cmd_fd)
> +{
> +       struct ibv_context *context = &context_ex->context;
> +
> +       ibverbs_device_hold(device);
> +
> +       context->device = device;
> +       context->cmd_fd = cmd_fd;
> +       context->async_fd = -1;
> +       pthread_mutex_init(&context->mutex, NULL);
> +
> +       context_ex->context.abi_compat = __VERBS_ABI_IS_EXTENDED;
> +       context_ex->sz = sizeof(*context_ex);
> +
> +       /*
> +        * In order to maintain backward/forward binary compatibility
> +        * with apps compiled against libibverbs-1.1.8 that use the
> +        * flow steering addition, we need to set the two
> +        * ABI_placeholder entries to match the driver set flow
> +        * entries.  This is because apps compiled against
> +        * libibverbs-1.1.8 use an inline ibv_create_flow and
> +        * ibv_destroy_flow function that looks in the placeholder
> +        * spots for the proper entry points.  For apps compiled
> +        * against libibverbs-1.1.9 and later, the inline functions
> +        * will be looking in the right place.
> +        */
> +       context_ex->ABI_placeholder1 =
> +               (void (*)(void))context_ex->ibv_create_flow;
> +       context_ex->ABI_placeholder2 =
> +               (void (*)(void))context_ex->ibv_destroy_flow;
> +
> +       context_ex->priv = calloc(1, sizeof(context_ex->priv));
> +       if (!context_ex->priv) {
> +               errno = ENOMEM;
> +               close(cmd_fd);
> +               return -1;
> +       }
> +
> +       return 0;
> +}
> +
> +/*
> + * Allocate and initialize a context structure. This is called to create the
> + * driver wrapper, and context_offset is the number of bytes into the wrapper
> + * structure where the verbs_context starts.
> + */
> +void *_verbs_init_and_alloc_context(struct ibv_device *device, int cmd_fd,
> +                                   size_t alloc_size,
> +                                   struct verbs_context *context_offset)
> +{
> +       void *drv_context;
> +       struct verbs_context *context;
> +
> +       drv_context = calloc(1, alloc_size);
> +       if (!drv_context) {
> +               errno = ENOMEM;
> +               close(cmd_fd);
> +               return NULL;
> +       }
> +
> +       context = (struct verbs_context *)((uint8_t *)drv_context +
> +                                          (uintptr_t)context_offset);

A wrapper macro would do better here?

> +
> +       if (verbs_init_context(context, device, cmd_fd))
> +               goto err_free;
> +
> +       return drv_context;
> +
> +err_free:
> +       free(drv_context);
> +       return NULL;
> +}
> +
> +/* Use the init_context flow to create a verbs_context */
> +static struct verbs_context *alloc_context(struct verbs_device *device,
> +                                          int cmd_fd)
> +{
> +       struct verbs_context *context;
> +
> +       context = _verbs_init_and_alloc_context(
> +               &device->device, cmd_fd,
> +               sizeof(*context) + device->size_of_context, NULL);
> +       if (!context)
> +               return NULL;
> +
> +       if (device->ops->init_context(device, &context->context, cmd_fd))
> +               goto err_uninit;
> +
> +       return context;
> +
> +err_uninit:
> +       verbs_uninit_context(context);
> +       free(context);
> +       return NULL;
> +}
> +
>  LATEST_SYMVER_FUNC(ibv_open_device, 1_1, "IBVERBS_1.1",
>                    struct ibv_context *,
>                    struct ibv_device *device)
>  {
>         struct verbs_device *verbs_device = verbs_get_device(device);
>         char *devpath;
> -       int cmd_fd, ret;
> -       struct ibv_context *context;
> +       int cmd_fd;
>         struct verbs_context *context_ex;
>
>         if (asprintf(&devpath, "/dev/infiniband/%s", device->dev_name) < 0)
> @@ -202,96 +304,50 @@ LATEST_SYMVER_FUNC(ibv_open_device, 1_1, "IBVERBS_1.1",
>         if (cmd_fd < 0)
>                 return NULL;
>
> -       if (!verbs_device->ops->init_context) {
> -               context = verbs_device->ops->alloc_context(device, cmd_fd);
> -               if (!context)
> -                       goto err;
> -       } else {
> -               struct verbs_ex_private *priv;
> -
> -               /* Library now allocates the context */
> -               context_ex = calloc(1, sizeof(*context_ex) +
> -                                      verbs_device->size_of_context);
> -               if (!context_ex) {
> -                       errno = ENOMEM;
> -                       goto err;
> -               }
> -
> -               priv = calloc(1, sizeof(*priv));
> -               if (!priv) {
> -                       errno = ENOMEM;
> -                       free(context_ex);
> -                       goto err;
> -               }
> -
> -               context_ex->priv = priv;
> -               context_ex->context.abi_compat  = __VERBS_ABI_IS_EXTENDED;
> -               context_ex->sz = sizeof(*context_ex);
> -
> -               context = &context_ex->context;
> -               ret = verbs_device->ops->init_context(verbs_device, context, cmd_fd);
> -               if (ret)
> -                       goto verbs_err;
> -               /*
> -                * In order to maintain backward/forward binary compatibility
> -                * with apps compiled against libibverbs-1.1.8 that use the
> -                * flow steering addition, we need to set the two
> -                * ABI_placeholder entries to match the driver set flow
> -                * entries.  This is because apps compiled against
> -                * libibverbs-1.1.8 use an inline ibv_create_flow and
> -                * ibv_destroy_flow function that looks in the placeholder
> -                * spots for the proper entry points.  For apps compiled
> -                * against libibverbs-1.1.9 and later, the inline functions
> -                * will be looking in the right place.
> -                */
> -               context_ex->ABI_placeholder1 = (void (*)(void)) context_ex->ibv_create_flow;
> -               context_ex->ABI_placeholder2 = (void (*)(void)) context_ex->ibv_destroy_flow;
> -
> -               if (context_ex->create_cq_ex) {
> -                       priv->create_cq_ex = context_ex->create_cq_ex;
> -                       context_ex->create_cq_ex = __lib_ibv_create_cq_ex;
> -               }
> -       }
> +       if (!verbs_device->ops->init_context)
> +               context_ex = verbs_device->ops->alloc_context(device, cmd_fd);
> +       else
> +               context_ex = alloc_context(verbs_device, cmd_fd);
>
> -       context->device = device;
> -       context->cmd_fd = cmd_fd;
> -       pthread_mutex_init(&context->mutex, NULL);
> +       /*
> +        * cmd_fd ownership is transferred into alloc_context, if it fails
> +        * then it closes cmd_fd and returns NULL
> +        */
> +       if (context_ex == NULL)
> +               return NULL;
>
> -       ibverbs_device_hold(device);
> +       if (context_ex->create_cq_ex) {
> +               context_ex->priv->create_cq_ex = context_ex->create_cq_ex;
> +               context_ex->create_cq_ex = __lib_ibv_create_cq_ex;
> +       }
>
> -       return context;
> +       return &context_ex->context;
> +}
>
> -verbs_err:
> +void verbs_uninit_context(struct verbs_context *context_ex)
> +{
>         free(context_ex->priv);
> -       free(context_ex);
> -err:
> -       close(cmd_fd);
> -       return NULL;
> +       close(context_ex->context.cmd_fd);
> +       close(context_ex->context.async_fd);
> +       ibverbs_device_put(context_ex->context.device);
>  }
>
>  LATEST_SYMVER_FUNC(ibv_close_device, 1_1, "IBVERBS_1.1",
>                    int,
>                    struct ibv_context *context)
>  {
> -       int async_fd = context->async_fd;
> -       int cmd_fd   = context->cmd_fd;
> -       struct verbs_context *context_ex;
>         struct verbs_device *verbs_device = verbs_get_device(context->device);
> -       struct ibv_device *device = context->device;
>
> -       context_ex = verbs_get_ctx(context);
> -       if (context_ex) {
> +       if (verbs_device->ops->uninit_context) {
> +               struct verbs_context *context_ex =
> +                       container_of(context, struct verbs_context, context);
> +
>                 verbs_device->ops->uninit_context(verbs_device, context);
> -               free(context_ex->priv);
> -               free(context_ex);
> +               verbs_uninit_context(context_ex);
>         } else {
>                 verbs_device->ops->free_context(context);
>         }
>
> -       close(async_fd);
> -       close(cmd_fd);
> -       ibverbs_device_put(device);
> -
>         return 0;
>  }
>
> diff --git a/libibverbs/driver.h b/libibverbs/driver.h
> index 4698ba4e609f34..809c4f5c8cdf39 100644
> --- a/libibverbs/driver.h
> +++ b/libibverbs/driver.h
> @@ -153,8 +153,8 @@ struct verbs_device_ops {
>         bool (*match_device)(struct verbs_sysfs_dev *sysfs_dev);
>
>         /* Old interface, do not use in new code. */
> -       struct ibv_context *(*alloc_context)(struct ibv_device *device,
> -                                            int cmd_fd);
> +       struct verbs_context *(*alloc_context)(struct ibv_device *device,
> +                                              int cmd_fd);
>         void (*free_context)(struct ibv_context *context);
>
>         /* New interface */
> @@ -205,13 +205,26 @@ void verbs_register_driver(const struct verbs_device_ops *ops);
>                 verbs_register_driver(&drv);                                   \
>         }
>
> +void *_verbs_init_and_alloc_context(struct ibv_device *device, int cmd_fd,
> +                                   size_t alloc_size,
> +                                   struct verbs_context *context_offset);
> +
> +#define verbs_init_and_alloc_context(ibdev, cmd_fd, drv_ctx_ptr, ctx_memb)     \
> +       ((typeof(drv_ctx_ptr))_verbs_init_and_alloc_context(                   \
> +               ibdev, cmd_fd, sizeof(*drv_ctx_ptr),                           \
> +               &((typeof(drv_ctx_ptr))NULL)->ctx_memb))
> +
> +int verbs_init_context(struct verbs_context *context_ex,
> +                      struct ibv_device *device, int cmd_fd);
> +void verbs_uninit_context(struct verbs_context *context);
> +
>  void verbs_init_cq(struct ibv_cq *cq, struct ibv_context *context,
>                        struct ibv_comp_channel *channel,
>                        void *cq_context);
>
> -int ibv_cmd_get_context(struct ibv_context *context, struct ibv_get_context *cmd,
> -                       size_t cmd_size, struct ibv_get_context_resp *resp,
> -                       size_t resp_size);
> +int ibv_cmd_get_context(struct verbs_context *context,
> +                       struct ibv_get_context *cmd, size_t cmd_size,
> +                       struct ibv_get_context_resp *resp, size_t resp_size);
>  int ibv_cmd_query_device(struct ibv_context *context,
>                          struct ibv_device_attr *device_attr,
>                          uint64_t *raw_fw_ver,
> diff --git a/libibverbs/libibverbs.map.in b/libibverbs/libibverbs.map.in
> index 3f635a94b82d58..b787b051b4c381 100644
> --- a/libibverbs/libibverbs.map.in
> +++ b/libibverbs/libibverbs.map.in
> @@ -113,6 +113,7 @@ IBVERBS_1.1 {
>  IBVERBS_PRIVATE_@IBVERBS_PABI_VERSION@ {
>         global:
>                 /* These historical symbols are now private to libibverbs */
> +               _verbs_init_and_alloc_context;
>                 ibv_cmd_alloc_mw;
>                 ibv_cmd_alloc_pd;
>                 ibv_cmd_attach_mcast;
> @@ -162,6 +163,7 @@ IBVERBS_PRIVATE_@IBVERBS_PABI_VERSION@ {
>                 ibv_query_gid_type;
>                 ibv_register_driver;
>                 verbs_register_driver_@IBVERBS_PABI_VERSION@;
> +               verbs_uninit_context;
>                 verbs_init_cq;
>                 ibv_cmd_modify_cq;
>  };
> diff --git a/providers/bnxt_re/main.c b/providers/bnxt_re/main.c
> index 998c9fe3313389..5e83f9d1c12f35 100644
> --- a/providers/bnxt_re/main.c
> +++ b/providers/bnxt_re/main.c
> @@ -111,14 +111,15 @@ static int bnxt_re_init_context(struct verbs_device *vdev,
>         struct bnxt_re_cntx_resp resp;
>         struct bnxt_re_dev *dev;
>         struct bnxt_re_context *cntx;
> +       struct verbs_context *verbs_ctx = verbs_get_ctx(ibvctx);
>
>         dev = to_bnxt_re_dev(&vdev->device);
>         cntx = to_bnxt_re_context(ibvctx);
>
>         memset(&resp, 0, sizeof(resp));
>         ibvctx->cmd_fd = cmd_fd;
> -       if (ibv_cmd_get_context(ibvctx, &cmd, sizeof(cmd),
> -                               &resp.resp, sizeof(resp)))
> +       if (ibv_cmd_get_context(verbs_ctx, &cmd, sizeof(cmd), &resp.resp,
> +                               sizeof(resp)))
>                 return errno;
>
>         cntx->dev_id = resp.dev_id;
> diff --git a/providers/cxgb3/iwch.c b/providers/cxgb3/iwch.c
> index da9179fbbe2a8d..d4d5a96ffd524e 100644
> --- a/providers/cxgb3/iwch.c
> +++ b/providers/cxgb3/iwch.c
> @@ -104,42 +104,38 @@ unsigned long iwch_page_size;
>  unsigned long iwch_page_shift;
>  unsigned long iwch_page_mask;
>
> -static struct ibv_context *iwch_alloc_context(struct ibv_device *ibdev,
> -                                             int cmd_fd)
> +static struct verbs_context *iwch_alloc_context(struct ibv_device *ibdev,
> +                                               int cmd_fd)
>  {
>         struct iwch_context *context;
>         struct ibv_get_context cmd;
>         struct iwch_alloc_ucontext_resp resp;
>         struct iwch_device *rhp = to_iwch_dev(ibdev);
>
> -       context = malloc(sizeof *context);
> +       context = verbs_init_and_alloc_context(ibdev, cmd_fd, context, ibv_ctx);
>         if (!context)
>                 return NULL;
>
> -       memset(context, 0, sizeof *context);
> -       context->ibv_ctx.cmd_fd = cmd_fd;
> -
>         if (ibv_cmd_get_context(&context->ibv_ctx, &cmd, sizeof cmd,
>                                 &resp.ibv_resp, sizeof resp))
>                 goto err_free;
>
> -       context->ibv_ctx.device = ibdev;
> -       context->ibv_ctx.ops = iwch_ctx_ops;
> +       context->ibv_ctx.context.ops = iwch_ctx_ops;
>
>         switch (rhp->hca_type) {
>         case CHELSIO_T3B:
>                 PDBG("%s T3B device\n", __FUNCTION__);
> -               context->ibv_ctx.ops.async_event = t3b_async_event;
> -               context->ibv_ctx.ops.post_send = t3b_post_send;
> -               context->ibv_ctx.ops.post_recv = t3b_post_recv;
> -               context->ibv_ctx.ops.poll_cq = t3b_poll_cq;
> +               context->ibv_ctx.context.ops.async_event = t3b_async_event;
> +               context->ibv_ctx.context.ops.post_send = t3b_post_send;
> +               context->ibv_ctx.context.ops.post_recv = t3b_post_recv;
> +               context->ibv_ctx.context.ops.poll_cq = t3b_poll_cq;
>                 break;
>         case CHELSIO_T3A:
>                 PDBG("%s T3A device\n", __FUNCTION__);
> -               context->ibv_ctx.ops.async_event = NULL;
> -               context->ibv_ctx.ops.post_send = t3a_post_send;
> -               context->ibv_ctx.ops.post_recv = t3a_post_recv;
> -               context->ibv_ctx.ops.poll_cq = t3a_poll_cq;
> +               context->ibv_ctx.context.ops.async_event = NULL;
> +               context->ibv_ctx.context.ops.post_send = t3a_post_send;
> +               context->ibv_ctx.context.ops.post_recv = t3a_post_recv;
> +               context->ibv_ctx.context.ops.poll_cq = t3a_poll_cq;
>                 break;
>         default:
>                 PDBG("%s unknown hca type %d\n", __FUNCTION__, rhp->hca_type);
> @@ -150,6 +146,7 @@ static struct ibv_context *iwch_alloc_context(struct ibv_device *ibdev,
>         return &context->ibv_ctx;
>
>  err_free:
> +       verbs_uninit_context(&context->ibv_ctx);
>         free(context);
>         return NULL;
>  }
> @@ -158,6 +155,7 @@ static void iwch_free_context(struct ibv_context *ibctx)
>  {
>         struct iwch_context *context = to_iwch_ctx(ibctx);
>
> +       verbs_uninit_context(&context->ibv_ctx);
>         free(context);
>  }
>
> diff --git a/providers/cxgb3/iwch.h b/providers/cxgb3/iwch.h
> index 1b95fec664ef11..0b8060cf7cfa8f 100644
> --- a/providers/cxgb3/iwch.h
> +++ b/providers/cxgb3/iwch.h
> @@ -71,7 +71,7 @@ static inline int t3a_device(struct iwch_device *dev)
>  }
>
>  struct iwch_context {
> -       struct ibv_context ibv_ctx;
> +       struct verbs_context ibv_ctx;
>  };
>
>  struct iwch_pd {
> @@ -111,7 +111,7 @@ static inline struct iwch_device *to_iwch_dev(struct ibv_device *ibdev)
>
>  static inline struct iwch_context *to_iwch_ctx(struct ibv_context *ibctx)
>  {
> -       return to_iwch_xxx(ctx, context);
> +       return container_of(ibctx, struct iwch_context, ibv_ctx.context);
>  }
>
>  static inline struct iwch_pd *to_iwch_pd(struct ibv_pd *ibpd)
> diff --git a/providers/cxgb4/dev.c b/providers/cxgb4/dev.c
> index b6775da8afeef7..3c309d9f5defb5 100644
> --- a/providers/cxgb4/dev.c
> +++ b/providers/cxgb4/dev.c
> @@ -96,8 +96,8 @@ static struct ibv_context_ops c4iw_ctx_ops = {
>         .req_notify_cq = c4iw_arm_cq,
>  };
>
> -static struct ibv_context *c4iw_alloc_context(struct ibv_device *ibdev,
> -                                             int cmd_fd)
> +static struct verbs_context *c4iw_alloc_context(struct ibv_device *ibdev,
> +                                               int cmd_fd)
>  {
>         struct c4iw_context *context;
>         struct ibv_get_context cmd;
> @@ -107,13 +107,10 @@ static struct ibv_context *c4iw_alloc_context(struct ibv_device *ibdev,
>         uint64_t raw_fw_ver;
>         struct ibv_device_attr attr;
>
> -       context = malloc(sizeof *context);
> +       context = verbs_init_and_alloc_context(ibdev, cmd_fd, context, ibv_ctx);
>         if (!context)
>                 return NULL;
>
> -       memset(context, 0, sizeof *context);
> -       context->ibv_ctx.cmd_fd = cmd_fd;
> -
>         resp.status_page_size = 0;
>         resp.reserved = 0;
>         if (ibv_cmd_get_context(&context->ibv_ctx, &cmd, sizeof cmd,
> @@ -133,8 +130,7 @@ static struct ibv_context *c4iw_alloc_context(struct ibv_device *ibdev,
>                         goto err_free;
>         }
>
> -       context->ibv_ctx.device = ibdev;
> -       context->ibv_ctx.ops = c4iw_ctx_ops;
> +       context->ibv_ctx.context.ops = c4iw_ctx_ops;
>
>         switch (rhp->chip_version) {
>         case CHELSIO_T6:
> @@ -143,11 +139,11 @@ static struct ibv_context *c4iw_alloc_context(struct ibv_device *ibdev,
>                 PDBG("%s T5/T4 device\n", __FUNCTION__);
>         case CHELSIO_T4:
>                 PDBG("%s T4 device\n", __FUNCTION__);
> -               context->ibv_ctx.ops.async_event = c4iw_async_event;
> -               context->ibv_ctx.ops.post_send = c4iw_post_send;
> -               context->ibv_ctx.ops.post_recv = c4iw_post_receive;
> -               context->ibv_ctx.ops.poll_cq = c4iw_poll_cq;
> -               context->ibv_ctx.ops.req_notify_cq = c4iw_arm_cq;
> +               context->ibv_ctx.context.ops.async_event = c4iw_async_event;
> +               context->ibv_ctx.context.ops.post_send = c4iw_post_send;
> +               context->ibv_ctx.context.ops.post_recv = c4iw_post_receive;
> +               context->ibv_ctx.context.ops.poll_cq = c4iw_poll_cq;
> +               context->ibv_ctx.context.ops.req_notify_cq = c4iw_arm_cq;
>                 break;
>         default:
>                 PDBG("%s unknown hca type %d\n", __FUNCTION__,
> @@ -159,8 +155,8 @@ static struct ibv_context *c4iw_alloc_context(struct ibv_device *ibdev,
>         if (!rhp->mmid2ptr) {
>                 int ret;
>
> -               ret = ibv_cmd_query_device(&context->ibv_ctx, &attr, &raw_fw_ver, &qcmd,
> -                                          sizeof qcmd);
> +               ret = ibv_cmd_query_device(&context->ibv_ctx.context, &attr,
> +                                          &raw_fw_ver, &qcmd, sizeof(qcmd));
>                 if (ret)
>                         goto err_unmap;
>                 rhp->max_mr = attr.max_mr;
> @@ -201,6 +197,7 @@ err_free:
>                 free(rhp->cqid2ptr);
>         if (rhp->mmid2ptr)
>                 free(rhp->cqid2ptr);
> +       verbs_uninit_context(&context->ibv_ctx);
>         free(context);
>         return NULL;
>  }
> @@ -211,6 +208,8 @@ static void c4iw_free_context(struct ibv_context *ibctx)
>
>         if (context->status_page_size)
>                 munmap(context->status_page, context->status_page_size);
> +
> +       verbs_uninit_context(&context->ibv_ctx);
>         free(context);
>  }
>
> diff --git a/providers/cxgb4/libcxgb4.h b/providers/cxgb4/libcxgb4.h
> index a5256f7e081770..893bd85d5f34b2 100644
> --- a/providers/cxgb4/libcxgb4.h
> +++ b/providers/cxgb4/libcxgb4.h
> @@ -80,7 +80,7 @@ static inline int dev_is_t4(struct c4iw_dev *dev)
>  }
>
>  struct c4iw_context {
> -       struct ibv_context ibv_ctx;
> +       struct verbs_context ibv_ctx;
>         struct t4_dev_status_page *status_page;
>         int status_page_size;
>  };
> @@ -129,7 +129,7 @@ static inline struct c4iw_dev *to_c4iw_dev(struct ibv_device *ibdev)
>
>  static inline struct c4iw_context *to_c4iw_context(struct ibv_context *ibctx)
>  {
> -       return to_c4iw_xxx(ctx, context);
> +       return container_of(ibctx, struct c4iw_context, ibv_ctx.context);
>  }
>
>  static inline struct c4iw_pd *to_c4iw_pd(struct ibv_pd *ibpd)
> diff --git a/providers/hfi1verbs/hfiverbs.c b/providers/hfi1verbs/hfiverbs.c
> index 7f8f5714db1630..6117f99fbc27a2 100644
> --- a/providers/hfi1verbs/hfiverbs.c
> +++ b/providers/hfi1verbs/hfiverbs.c
> @@ -123,41 +123,42 @@ static struct ibv_context_ops hfi1_ctx_ops = {
>         .detach_mcast   = ibv_cmd_detach_mcast
>  };
>
> -static struct ibv_context *hfi1_alloc_context(struct ibv_device *ibdev,
> -                                              int cmd_fd)
> +static struct verbs_context *hfi1_alloc_context(struct ibv_device *ibdev,
> +                                               int cmd_fd)
>  {
>         struct hfi1_context         *context;
>         struct ibv_get_context       cmd;
>         struct ibv_get_context_resp  resp;
>         struct hfi1_device         *dev;
>
> -       context = malloc(sizeof *context);
> +       context = verbs_init_and_alloc_context(ibdev, cmd_fd, context, ibv_ctx);
>         if (!context)
>                 return NULL;
> -       memset(context, 0, sizeof *context);
> -       context->ibv_ctx.cmd_fd = cmd_fd;
> +
>         if (ibv_cmd_get_context(&context->ibv_ctx, &cmd,
>                                 sizeof cmd, &resp, sizeof resp))
>                 goto err_free;
>
> -       context->ibv_ctx.ops = hfi1_ctx_ops;
> +       context->ibv_ctx.context.ops = hfi1_ctx_ops;
>         dev = to_idev(ibdev);
>         if (dev->abi_version == 1) {
> -               context->ibv_ctx.ops.create_cq     = hfi1_create_cq_v1;
> -               context->ibv_ctx.ops.poll_cq       = ibv_cmd_poll_cq;
> -               context->ibv_ctx.ops.resize_cq     = hfi1_resize_cq_v1;
> -               context->ibv_ctx.ops.destroy_cq    = hfi1_destroy_cq_v1;
> -               context->ibv_ctx.ops.create_srq    = hfi1_create_srq_v1;
> -               context->ibv_ctx.ops.destroy_srq   = hfi1_destroy_srq_v1;
> -               context->ibv_ctx.ops.modify_srq    = hfi1_modify_srq_v1;
> -               context->ibv_ctx.ops.post_srq_recv = ibv_cmd_post_srq_recv;
> -               context->ibv_ctx.ops.create_qp     = hfi1_create_qp_v1;
> -               context->ibv_ctx.ops.destroy_qp    = hfi1_destroy_qp_v1;
> -               context->ibv_ctx.ops.post_recv     = ibv_cmd_post_recv;
> +               context->ibv_ctx.context.ops.create_cq = hfi1_create_cq_v1;
> +               context->ibv_ctx.context.ops.poll_cq = ibv_cmd_poll_cq;
> +               context->ibv_ctx.context.ops.resize_cq = hfi1_resize_cq_v1;
> +               context->ibv_ctx.context.ops.destroy_cq = hfi1_destroy_cq_v1;
> +               context->ibv_ctx.context.ops.create_srq = hfi1_create_srq_v1;
> +               context->ibv_ctx.context.ops.destroy_srq = hfi1_destroy_srq_v1;
> +               context->ibv_ctx.context.ops.modify_srq = hfi1_modify_srq_v1;
> +               context->ibv_ctx.context.ops.post_srq_recv =
> +                       ibv_cmd_post_srq_recv;
> +               context->ibv_ctx.context.ops.create_qp = hfi1_create_qp_v1;
> +               context->ibv_ctx.context.ops.destroy_qp = hfi1_destroy_qp_v1;
> +               context->ibv_ctx.context.ops.post_recv = ibv_cmd_post_recv;
>         }
>         return &context->ibv_ctx;
>
>  err_free:
> +       verbs_uninit_context(&context->ibv_ctx);
>         free(context);
>         return NULL;
>  }
> @@ -166,6 +167,7 @@ static void hfi1_free_context(struct ibv_context *ibctx)
>  {
>         struct hfi1_context *context = to_ictx(ibctx);
>
> +       verbs_uninit_context(&context->ibv_ctx);
>         free(context);
>  }
>
> diff --git a/providers/hfi1verbs/hfiverbs.h b/providers/hfi1verbs/hfiverbs.h
> index e672dda4982527..e7a05a0c0a83db 100644
> --- a/providers/hfi1verbs/hfiverbs.h
> +++ b/providers/hfi1verbs/hfiverbs.h
> @@ -74,7 +74,7 @@ struct hfi1_device {
>  };
>
>  struct hfi1_context {
> -       struct ibv_context      ibv_ctx;
> +       struct verbs_context    ibv_ctx;
>  };
>
>  /*
> @@ -158,7 +158,7 @@ struct hfi1_srq {
>
>  static inline struct hfi1_context *to_ictx(struct ibv_context *ibctx)
>  {
> -       return to_ixxx(ctx, context);
> +       return container_of(ibctx, struct hfi1_context, ibv_ctx.context);
>  }
>
>  static inline struct hfi1_device *to_idev(struct ibv_device *ibdev)
> diff --git a/providers/hns/hns_roce_u.c b/providers/hns/hns_roce_u.c
> index 489b71614614fe..781825b3782044 100644
> --- a/providers/hns/hns_roce_u.c
> +++ b/providers/hns/hns_roce_u.c
> @@ -61,8 +61,8 @@ static const struct verbs_match_ent hca_table[] = {
>         {}
>  };
>
> -static struct ibv_context *hns_roce_alloc_context(struct ibv_device *ibdev,
> -                                                 int cmd_fd)
> +static struct verbs_context *hns_roce_alloc_context(struct ibv_device *ibdev,
> +                                                   int cmd_fd)
>  {
>         int i;
>         struct ibv_get_context cmd;
> @@ -71,11 +71,10 @@ static struct ibv_context *hns_roce_alloc_context(struct ibv_device *ibdev,
>         struct hns_roce_alloc_ucontext_resp resp;
>         struct hns_roce_device *hr_dev = to_hr_dev(ibdev);
>
> -       context = calloc(1, sizeof(*context));
> +       context = verbs_init_and_alloc_context(ibdev, cmd_fd, context, ibv_ctx);
>         if (!context)
>                 return NULL;
>
> -       context->ibv_ctx.cmd_fd = cmd_fd;
>         if (ibv_cmd_get_context(&context->ibv_ctx, &cmd, sizeof(cmd),
>                                 &resp.ibv_resp, sizeof(resp)))
>                 goto err_free;
> @@ -113,28 +112,28 @@ static struct ibv_context *hns_roce_alloc_context(struct ibv_device *ibdev,
>
>         pthread_spin_init(&context->uar_lock, PTHREAD_PROCESS_PRIVATE);
>
> -       context->ibv_ctx.ops.query_device  = hns_roce_u_query_device;
> -       context->ibv_ctx.ops.query_port    = hns_roce_u_query_port;
> -       context->ibv_ctx.ops.alloc_pd      = hns_roce_u_alloc_pd;
> -       context->ibv_ctx.ops.dealloc_pd    = hns_roce_u_free_pd;
> -       context->ibv_ctx.ops.reg_mr        = hns_roce_u_reg_mr;
> -       context->ibv_ctx.ops.rereg_mr      = hns_roce_u_rereg_mr;
> -       context->ibv_ctx.ops.dereg_mr      = hns_roce_u_dereg_mr;
> -
> -       context->ibv_ctx.ops.create_cq     = hns_roce_u_create_cq;
> -       context->ibv_ctx.ops.poll_cq       = hr_dev->u_hw->poll_cq;
> -       context->ibv_ctx.ops.req_notify_cq = hr_dev->u_hw->arm_cq;
> -       context->ibv_ctx.ops.cq_event      = hns_roce_u_cq_event;
> -       context->ibv_ctx.ops.destroy_cq    = hns_roce_u_destroy_cq;
> -
> -       context->ibv_ctx.ops.create_qp     = hns_roce_u_create_qp;
> -       context->ibv_ctx.ops.query_qp      = hns_roce_u_query_qp;
> -       context->ibv_ctx.ops.modify_qp     = hr_dev->u_hw->modify_qp;
> -       context->ibv_ctx.ops.destroy_qp    = hr_dev->u_hw->destroy_qp;
> -       context->ibv_ctx.ops.post_send     = hr_dev->u_hw->post_send;
> -       context->ibv_ctx.ops.post_recv     = hr_dev->u_hw->post_recv;
> -
> -       if (hns_roce_u_query_device(&context->ibv_ctx, &dev_attrs))
> +       context->ibv_ctx.context.ops.query_device  = hns_roce_u_query_device;
> +       context->ibv_ctx.context.ops.query_port    = hns_roce_u_query_port;
> +       context->ibv_ctx.context.ops.alloc_pd      = hns_roce_u_alloc_pd;
> +       context->ibv_ctx.context.ops.dealloc_pd    = hns_roce_u_free_pd;
> +       context->ibv_ctx.context.ops.reg_mr        = hns_roce_u_reg_mr;
> +       context->ibv_ctx.context.ops.rereg_mr      = hns_roce_u_rereg_mr;
> +       context->ibv_ctx.context.ops.dereg_mr      = hns_roce_u_dereg_mr;
> +
> +       context->ibv_ctx.context.ops.create_cq     = hns_roce_u_create_cq;
> +       context->ibv_ctx.context.ops.poll_cq       = hr_dev->u_hw->poll_cq;
> +       context->ibv_ctx.context.ops.req_notify_cq = hr_dev->u_hw->arm_cq;
> +       context->ibv_ctx.context.ops.cq_event      = hns_roce_u_cq_event;
> +       context->ibv_ctx.context.ops.destroy_cq    = hns_roce_u_destroy_cq;
> +
> +       context->ibv_ctx.context.ops.create_qp     = hns_roce_u_create_qp;
> +       context->ibv_ctx.context.ops.query_qp      = hns_roce_u_query_qp;
> +       context->ibv_ctx.context.ops.modify_qp     = hr_dev->u_hw->modify_qp;
> +       context->ibv_ctx.context.ops.destroy_qp    = hr_dev->u_hw->destroy_qp;
> +       context->ibv_ctx.context.ops.post_send     = hr_dev->u_hw->post_send;
> +       context->ibv_ctx.context.ops.post_recv     = hr_dev->u_hw->post_recv;
> +
> +       if (hns_roce_u_query_device(&context->ibv_ctx.context, &dev_attrs))
>                 goto tptr_free;
>
>         context->max_qp_wr = dev_attrs.max_qp_wr;
> @@ -155,6 +154,7 @@ db_free:
>         context->uar = NULL;
>
>  err_free:
> +       verbs_uninit_context(&context->ibv_ctx);
>         free(context);
>         return NULL;
>  }
> @@ -167,6 +167,7 @@ static void hns_roce_free_context(struct ibv_context *ibctx)
>         if (to_hr_dev(ibctx->device)->hw_version == HNS_ROCE_HW_VER1)
>                 munmap(context->cq_tptr_base, HNS_ROCE_CQ_DB_BUF_SIZE);
>
> +       verbs_uninit_context(&context->ibv_ctx);
>         free(context);
>  }
>
> diff --git a/providers/hns/hns_roce_u.h b/providers/hns/hns_roce_u.h
> index 101320b1f8f3ad..02912468e68a65 100644
> --- a/providers/hns/hns_roce_u.h
> +++ b/providers/hns/hns_roce_u.h
> @@ -94,7 +94,7 @@ struct hns_roce_buf {
>  };
>
>  struct hns_roce_context {
> -       struct ibv_context              ibv_ctx;
> +       struct verbs_context            ibv_ctx;
>         void                            *uar;
>         pthread_spinlock_t              uar_lock;
>
> @@ -221,7 +221,7 @@ static inline struct hns_roce_device *to_hr_dev(struct ibv_device *ibv_dev)
>
>  static inline struct hns_roce_context *to_hr_ctx(struct ibv_context *ibv_ctx)
>  {
> -       return container_of(ibv_ctx, struct hns_roce_context, ibv_ctx);
> +       return container_of(ibv_ctx, struct hns_roce_context, ibv_ctx.context);
>  }
>
>  static inline struct hns_roce_pd *to_hr_pd(struct ibv_pd *ibv_pd)
> diff --git a/providers/hns/hns_roce_u_verbs.c b/providers/hns/hns_roce_u_verbs.c
> index 046f0a4b849712..3def78d25a9a71 100644
> --- a/providers/hns/hns_roce_u_verbs.c
> +++ b/providers/hns/hns_roce_u_verbs.c
> @@ -208,7 +208,8 @@ static void hns_roce_set_sq_sizes(struct hns_roce_qp *qp,
>
>  static int hns_roce_verify_cq(int *cqe, struct hns_roce_context *context)
>  {
> -       struct hns_roce_device *hr_dev = to_hr_dev(context->ibv_ctx.device);
> +       struct hns_roce_device *hr_dev =
> +               to_hr_dev(context->ibv_ctx.context.device);
>
>         if (hr_dev->hw_version == HNS_ROCE_HW_VER1)
>                 if (*cqe < HNS_ROCE_MIN_CQE_NUM) {
> @@ -328,7 +329,8 @@ int hns_roce_u_destroy_cq(struct ibv_cq *cq)
>  static int hns_roce_verify_qp(struct ibv_qp_init_attr *attr,
>                               struct hns_roce_context *context)
>  {
> -       struct hns_roce_device *hr_dev = to_hr_dev(context->ibv_ctx.device);
> +       struct hns_roce_device *hr_dev =
> +               to_hr_dev(context->ibv_ctx.context.device);
>
>         if (hr_dev->hw_version == HNS_ROCE_HW_VER1) {
>                 if (attr->cap.max_send_wr < HNS_ROCE_MIN_WQE_NUM) {
> diff --git a/providers/i40iw/i40iw_umain.c b/providers/i40iw/i40iw_umain.c
> index 77c1ced812499b..6ec40895efcfe0 100644
> --- a/providers/i40iw/i40iw_umain.c
> +++ b/providers/i40iw/i40iw_umain.c
> @@ -131,19 +131,18 @@ static struct ibv_context_ops i40iw_uctx_ops = {
>   * context and getting back resource information to return as ibv_context.
>   */
>
> -static struct ibv_context *i40iw_ualloc_context(struct ibv_device *ibdev, int cmd_fd)
> +static struct verbs_context *i40iw_ualloc_context(struct ibv_device *ibdev,
> +                                                 int cmd_fd)
>  {
>         struct ibv_pd *ibv_pd;
>         struct i40iw_uvcontext *iwvctx;
>         struct i40iw_get_context cmd;
>         struct i40iw_ualloc_ucontext_resp resp;
>
> -       iwvctx = malloc(sizeof(*iwvctx));
> +       iwvctx = verbs_init_and_alloc_context(ibdev, cmd_fd, iwvctx, ibv_ctx);
>         if (!iwvctx)
>                 return NULL;
>
> -       memset(iwvctx, 0, sizeof(*iwvctx));
> -       iwvctx->ibv_ctx.cmd_fd = cmd_fd;
>         cmd.userspace_ver = I40IW_ABI_VER;
>         memset(&resp, 0, sizeof(resp));
>         if (ibv_cmd_get_context(&iwvctx->ibv_ctx, (struct ibv_get_context *)&cmd,
> @@ -162,24 +161,24 @@ static struct ibv_context *i40iw_ualloc_context(struct ibv_device *ibdev, int cm
>                 goto err_free;
>         }
>
> -       iwvctx->ibv_ctx.device = ibdev;
> -       iwvctx->ibv_ctx.ops = i40iw_uctx_ops;
> +       iwvctx->ibv_ctx.context.ops = i40iw_uctx_ops;
>         iwvctx->max_pds = resp.max_pds;
>         iwvctx->max_qps = resp.max_qps;
>         iwvctx->wq_size = resp.wq_size;
>         iwvctx->abi_ver = resp.kernel_ver;
>
>         i40iw_device_init_uk(&iwvctx->dev);
> -       ibv_pd = i40iw_ualloc_pd(&iwvctx->ibv_ctx);
> +       ibv_pd = i40iw_ualloc_pd(&iwvctx->ibv_ctx.context);
>         if (!ibv_pd)
>                 goto err_free;
> -       ibv_pd->context = &iwvctx->ibv_ctx;
> +       ibv_pd->context = &iwvctx->ibv_ctx.context;
>         iwvctx->iwupd = to_i40iw_upd(ibv_pd);
>
>         return &iwvctx->ibv_ctx;
>
>  err_free:
>         fprintf(stderr, PFX "%s: failed to allocate context for device.\n", __func__);
> +       verbs_uninit_context(&iwvctx->ibv_ctx);
>         free(iwvctx);
>
>         return NULL;
> @@ -195,6 +194,7 @@ static void i40iw_ufree_context(struct ibv_context *ibctx)
>
>         i40iw_ufree_pd(&iwvctx->iwupd->ibv_pd);
>
> +       verbs_uninit_context(&iwvctx->ibv_ctx);
>         free(iwvctx);
>  }
>
> diff --git a/providers/i40iw/i40iw_umain.h b/providers/i40iw/i40iw_umain.h
> index 109aba6bd92ef4..a2f4fa8f6b6bd9 100644
> --- a/providers/i40iw/i40iw_umain.h
> +++ b/providers/i40iw/i40iw_umain.h
> @@ -83,7 +83,7 @@ struct i40iw_upd {
>  };
>
>  struct i40iw_uvcontext {
> -       struct ibv_context ibv_ctx;
> +       struct verbs_context ibv_ctx;
>         struct i40iw_upd *iwupd;
>         uint32_t max_pds;       /* maximum pds allowed for this user process */
>         uint32_t max_qps;       /* maximum qps allowed for this user process */
> @@ -137,7 +137,7 @@ static inline struct i40iw_udevice *to_i40iw_udev(struct ibv_device *ibdev)
>
>  static inline struct i40iw_uvcontext *to_i40iw_uctx(struct ibv_context *ibctx)
>  {
> -       return to_i40iw_uxxx(ctx, vcontext);
> +       return container_of(ibctx, struct i40iw_uvcontext, ibv_ctx.context);
>  }
>
>  static inline struct i40iw_upd *to_i40iw_upd(struct ibv_pd *ibpd)
> diff --git a/providers/ipathverbs/ipathverbs.c b/providers/ipathverbs/ipathverbs.c
> index 449abb0489955a..3f7f170ed6b986 100644
> --- a/providers/ipathverbs/ipathverbs.c
> +++ b/providers/ipathverbs/ipathverbs.c
> @@ -122,41 +122,42 @@ static struct ibv_context_ops ipath_ctx_ops = {
>         .detach_mcast   = ibv_cmd_detach_mcast
>  };
>
> -static struct ibv_context *ipath_alloc_context(struct ibv_device *ibdev,
> -                                              int cmd_fd)
> +static struct verbs_context *ipath_alloc_context(struct ibv_device *ibdev,
> +                                                int cmd_fd)
>  {
>         struct ipath_context        *context;
>         struct ibv_get_context       cmd;
>         struct ibv_get_context_resp  resp;
>         struct ipath_device         *dev;
>
> -       context = malloc(sizeof *context);
> +       context = verbs_init_and_alloc_context(ibdev, cmd_fd, context, ibv_ctx);
>         if (!context)
>                 return NULL;
> -       memset(context, 0, sizeof *context);
> -       context->ibv_ctx.cmd_fd = cmd_fd;
> +
>         if (ibv_cmd_get_context(&context->ibv_ctx, &cmd,
>                                 sizeof cmd, &resp, sizeof resp))
>                 goto err_free;
>
> -       context->ibv_ctx.ops = ipath_ctx_ops;
> +       context->ibv_ctx.context.ops = ipath_ctx_ops;
>         dev = to_idev(ibdev);
>         if (dev->abi_version == 1) {
> -               context->ibv_ctx.ops.create_cq     = ipath_create_cq_v1;
> -               context->ibv_ctx.ops.poll_cq       = ibv_cmd_poll_cq;
> -               context->ibv_ctx.ops.resize_cq     = ipath_resize_cq_v1;
> -               context->ibv_ctx.ops.destroy_cq    = ipath_destroy_cq_v1;
> -               context->ibv_ctx.ops.create_srq    = ipath_create_srq_v1;
> -               context->ibv_ctx.ops.destroy_srq   = ipath_destroy_srq_v1;
> -               context->ibv_ctx.ops.modify_srq    = ipath_modify_srq_v1;
> -               context->ibv_ctx.ops.post_srq_recv = ibv_cmd_post_srq_recv;
> -               context->ibv_ctx.ops.create_qp     = ipath_create_qp_v1;
> -               context->ibv_ctx.ops.destroy_qp    = ipath_destroy_qp_v1;
> -               context->ibv_ctx.ops.post_recv     = ibv_cmd_post_recv;
> +               context->ibv_ctx.context.ops.create_cq = ipath_create_cq_v1;
> +               context->ibv_ctx.context.ops.poll_cq = ibv_cmd_poll_cq;
> +               context->ibv_ctx.context.ops.resize_cq = ipath_resize_cq_v1;
> +               context->ibv_ctx.context.ops.destroy_cq = ipath_destroy_cq_v1;
> +               context->ibv_ctx.context.ops.create_srq = ipath_create_srq_v1;
> +               context->ibv_ctx.context.ops.destroy_srq = ipath_destroy_srq_v1;
> +               context->ibv_ctx.context.ops.modify_srq = ipath_modify_srq_v1;
> +               context->ibv_ctx.context.ops.post_srq_recv =
> +                       ibv_cmd_post_srq_recv;
> +               context->ibv_ctx.context.ops.create_qp = ipath_create_qp_v1;
> +               context->ibv_ctx.context.ops.destroy_qp = ipath_destroy_qp_v1;
> +               context->ibv_ctx.context.ops.post_recv = ibv_cmd_post_recv;
>         }
>         return &context->ibv_ctx;
>
>  err_free:
> +       verbs_uninit_context(&context->ibv_ctx);
>         free(context);
>         return NULL;
>  }
> @@ -165,6 +166,7 @@ static void ipath_free_context(struct ibv_context *ibctx)
>  {
>         struct ipath_context *context = to_ictx(ibctx);
>
> +       verbs_uninit_context(&context->ibv_ctx);
>         free(context);
>  }
>
> diff --git a/providers/ipathverbs/ipathverbs.h b/providers/ipathverbs/ipathverbs.h
> index 5f2658e7942c8b..d26a2a1b29009e 100644
> --- a/providers/ipathverbs/ipathverbs.h
> +++ b/providers/ipathverbs/ipathverbs.h
> @@ -54,7 +54,7 @@ struct ipath_device {
>  };
>
>  struct ipath_context {
> -       struct ibv_context      ibv_ctx;
> +       struct verbs_context    ibv_ctx;
>  };
>
>  /*
> @@ -137,7 +137,7 @@ struct ipath_srq {
>
>  static inline struct ipath_context *to_ictx(struct ibv_context *ibctx)
>  {
> -       return to_ixxx(ctx, context);
> +       return container_of(ibctx, struct ipath_context, ibv_ctx.context);
>  }
>
>  static inline struct ipath_device *to_idev(struct ibv_device *ibdev)
> diff --git a/providers/mlx4/mlx4.c b/providers/mlx4/mlx4.c
> index d2ccd328625c80..56bf1298b48734 100644
> --- a/providers/mlx4/mlx4.c
> +++ b/providers/mlx4/mlx4.c
> @@ -167,16 +167,16 @@ static int mlx4_init_context(struct verbs_device *v_device,
>
>         mlx4_read_env();
>         if (dev->abi_version <= MLX4_UVERBS_NO_DEV_CAPS_ABI_VERSION) {
> -               if (ibv_cmd_get_context(ibv_ctx, &cmd, sizeof cmd,
> -                                       &resp_v3.ibv_resp, sizeof resp_v3))
> +               if (ibv_cmd_get_context(verbs_ctx, &cmd, sizeof(cmd),
> +                                       &resp_v3.ibv_resp, sizeof(resp_v3)))
>                         return errno;
>
>                 context->num_qps  = resp_v3.qp_tab_size;
>                 bf_reg_size       = resp_v3.bf_reg_size;
>                 context->cqe_size = sizeof (struct mlx4_cqe);
>         } else  {
> -               if (ibv_cmd_get_context(ibv_ctx, &cmd, sizeof cmd,
> -                                       &resp.ibv_resp, sizeof resp))
> +               if (ibv_cmd_get_context(verbs_ctx, &cmd, sizeof(cmd),
> +                                       &resp.ibv_resp, sizeof(resp)))
>                         return errno;
>
>                 context->num_qps  = resp.qp_tab_size;
> diff --git a/providers/mlx5/mlx5.c b/providers/mlx5/mlx5.c
> index 36486218e31d81..a829cd5eb26473 100644
> --- a/providers/mlx5/mlx5.c
> +++ b/providers/mlx5/mlx5.c
> @@ -549,7 +549,9 @@ static int mlx5_cmd_get_context(struct mlx5_context *context,
>                                 struct mlx5_alloc_ucontext_resp *resp,
>                                 size_t resp_len)
>  {
> -       if (!ibv_cmd_get_context(&context->ibv_ctx, &req->ibv_req,
> +       struct verbs_context *verbs_ctx = verbs_get_ctx(&context->ibv_ctx);
> +
> +       if (!ibv_cmd_get_context(verbs_ctx, &req->ibv_req,
>                                  req_len, &resp->ibv_resp, resp_len))
>                 return 0;
>
> @@ -572,12 +574,12 @@ static int mlx5_cmd_get_context(struct mlx5_context *context,
>          * to do so. If zero is a valid response, we will add a new
>          * field that indicates whether the request was handled.
>          */
> -       if (!ibv_cmd_get_context(&context->ibv_ctx, &req->ibv_req,
> +       if (!ibv_cmd_get_context(verbs_ctx, &req->ibv_req,
>                                  offsetof(struct mlx5_alloc_ucontext, lib_caps),
>                                  &resp->ibv_resp, resp_len))
>                 return 0;
>
> -       return ibv_cmd_get_context(&context->ibv_ctx, &req->ibv_req,
> +       return ibv_cmd_get_context(verbs_ctx, &req->ibv_req,
>                                    offsetof(struct mlx5_alloc_ucontext,
>                                             cqe_version),
>                                    &resp->ibv_resp, resp_len);
> diff --git a/providers/mthca/mthca.c b/providers/mthca/mthca.c
> index 511b8d5139af9c..15827391986d3a 100644
> --- a/providers/mthca/mthca.c
> +++ b/providers/mthca/mthca.c
> @@ -114,19 +114,18 @@ static struct ibv_context_ops mthca_ctx_ops = {
>         .detach_mcast  = ibv_cmd_detach_mcast
>  };
>
> -static struct ibv_context *mthca_alloc_context(struct ibv_device *ibdev, int cmd_fd)
> +static struct verbs_context *mthca_alloc_context(struct ibv_device *ibdev,
> +                                                int cmd_fd)
>  {
>         struct mthca_context            *context;
>         struct ibv_get_context           cmd;
>         struct mthca_alloc_ucontext_resp resp;
>         int                              i;
>
> -       context = calloc(1, sizeof *context);
> +       context = verbs_init_and_alloc_context(ibdev, cmd_fd, context, ibv_ctx);
>         if (!context)
>                 return NULL;
>
> -       context->ibv_ctx.cmd_fd = cmd_fd;
> -
>         if (ibv_cmd_get_context(&context->ibv_ctx, &cmd, sizeof cmd,
>                                 &resp.ibv_resp, sizeof resp))
>                 goto err_free;
> @@ -135,13 +134,7 @@ static struct ibv_context *mthca_alloc_context(struct ibv_device *ibdev, int cmd
>         context->qp_table_shift = ffs(context->num_qps) - 1 - MTHCA_QP_TABLE_BITS;
>         context->qp_table_mask  = (1 << context->qp_table_shift) - 1;
>
> -       /*
> -        * Need to set ibv_ctx.device because mthca_is_memfree() will
> -        * look at it to figure out the HCA type.
> -        */
> -       context->ibv_ctx.device = ibdev;
> -
> -       if (mthca_is_memfree(&context->ibv_ctx)) {
> +       if (mthca_is_memfree(&context->ibv_ctx.context)) {
>                 context->db_tab = mthca_alloc_db_tab(resp.uarc_size);
>                 if (!context->db_tab)
>                         goto err_free;
> @@ -159,26 +152,28 @@ static struct ibv_context *mthca_alloc_context(struct ibv_device *ibdev, int cmd
>
>         pthread_spin_init(&context->uar_lock, PTHREAD_PROCESS_PRIVATE);
>
> -       context->pd = mthca_alloc_pd(&context->ibv_ctx);
> +       context->pd = mthca_alloc_pd(&context->ibv_ctx.context);
>         if (!context->pd)
>                 goto err_unmap;
>
> -       context->pd->context = &context->ibv_ctx;
> +       context->pd->context = &context->ibv_ctx.context;
>
> -       context->ibv_ctx.ops = mthca_ctx_ops;
> +       context->ibv_ctx.context.ops = mthca_ctx_ops;
>
> -       if (mthca_is_memfree(&context->ibv_ctx)) {
> -               context->ibv_ctx.ops.req_notify_cq = mthca_arbel_arm_cq;
> -               context->ibv_ctx.ops.cq_event      = mthca_arbel_cq_event;
> -               context->ibv_ctx.ops.post_send     = mthca_arbel_post_send;
> -               context->ibv_ctx.ops.post_recv     = mthca_arbel_post_recv;
> -               context->ibv_ctx.ops.post_srq_recv = mthca_arbel_post_srq_recv;
> +       if (mthca_is_memfree(&context->ibv_ctx.context)) {
> +               context->ibv_ctx.context.ops.req_notify_cq = mthca_arbel_arm_cq;
> +               context->ibv_ctx.context.ops.cq_event = mthca_arbel_cq_event;
> +               context->ibv_ctx.context.ops.post_send = mthca_arbel_post_send;
> +               context->ibv_ctx.context.ops.post_recv = mthca_arbel_post_recv;
> +               context->ibv_ctx.context.ops.post_srq_recv =
> +                       mthca_arbel_post_srq_recv;
>         } else {
> -               context->ibv_ctx.ops.req_notify_cq = mthca_tavor_arm_cq;
> -               context->ibv_ctx.ops.cq_event      = NULL;
> -               context->ibv_ctx.ops.post_send     = mthca_tavor_post_send;
> -               context->ibv_ctx.ops.post_recv     = mthca_tavor_post_recv;
> -               context->ibv_ctx.ops.post_srq_recv = mthca_tavor_post_srq_recv;
> +               context->ibv_ctx.context.ops.req_notify_cq = mthca_tavor_arm_cq;
> +               context->ibv_ctx.context.ops.cq_event = NULL;
> +               context->ibv_ctx.context.ops.post_send = mthca_tavor_post_send;
> +               context->ibv_ctx.context.ops.post_recv = mthca_tavor_post_recv;
> +               context->ibv_ctx.context.ops.post_srq_recv =
> +                       mthca_tavor_post_srq_recv;
>         }
>
>         return &context->ibv_ctx;
> @@ -190,6 +185,7 @@ err_db_tab:
>         mthca_free_db_tab(context->db_tab);
>
>  err_free:
> +       verbs_uninit_context(&context->ibv_ctx);
>         free(context);
>         return NULL;
>  }
> @@ -201,6 +197,8 @@ static void mthca_free_context(struct ibv_context *ibctx)
>         mthca_free_pd(context->pd);
>         munmap(context->uar, to_mdev(ibctx->device)->page_size);
>         mthca_free_db_tab(context->db_tab);
> +
> +       verbs_uninit_context(&context->ibv_ctx);
>         free(context);
>  }
>
> diff --git a/providers/mthca/mthca.h b/providers/mthca/mthca.h
> index a67acf46c7c56d..d788f7613b439c 100644
> --- a/providers/mthca/mthca.h
> +++ b/providers/mthca/mthca.h
> @@ -97,7 +97,7 @@ struct mthca_device {
>  struct mthca_db_table;
>
>  struct mthca_context {
> -       struct ibv_context     ibv_ctx;
> +       struct verbs_context     ibv_ctx;
>         void                  *uar;
>         pthread_spinlock_t     uar_lock;
>         struct mthca_db_table *db_tab;
> @@ -229,7 +229,7 @@ static inline struct mthca_device *to_mdev(struct ibv_device *ibdev)
>
>  static inline struct mthca_context *to_mctx(struct ibv_context *ibctx)
>  {
> -       return to_mxxx(ctx, context);
> +       return container_of(ibctx, struct mthca_context, ibv_ctx.context);
>  }
>
>  static inline struct mthca_pd *to_mpd(struct ibv_pd *ibpd)
> diff --git a/providers/nes/nes_umain.c b/providers/nes/nes_umain.c
> index bd0b6ac68cec40..a5ae678ecfe11c 100644
> --- a/providers/nes/nes_umain.c
> +++ b/providers/nes/nes_umain.c
> @@ -98,7 +98,8 @@ static struct ibv_context_ops nes_uctx_ops = {
>  /**
>   * nes_ualloc_context
>   */
> -static struct ibv_context *nes_ualloc_context(struct ibv_device *ibdev, int cmd_fd)
> +static struct verbs_context *nes_ualloc_context(struct ibv_device *ibdev,
> +                                               int cmd_fd)
>  {
>         struct ibv_pd *ibv_pd;
>         struct nes_uvcontext *nesvctx;
> @@ -109,16 +110,14 @@ static struct ibv_context *nes_ualloc_context(struct ibv_device *ibdev, int cmd_
>
>         page_size = sysconf(_SC_PAGESIZE);
>
> -       nesvctx = malloc(sizeof *nesvctx);
> +       nesvctx = verbs_init_and_alloc_context(ibdev, cmd_fd, nesvctx, ibv_ctx);
>         if (!nesvctx)
>                 return NULL;
>
> -       memset(nesvctx, 0, sizeof *nesvctx);
> -       nesvctx->ibv_ctx.cmd_fd = cmd_fd;
>         cmd.userspace_ver = NES_ABI_USERSPACE_VER;
>
>         if (ibv_cmd_get_context(&nesvctx->ibv_ctx, (struct ibv_get_context *)&cmd, sizeof cmd,
> -                       &resp.ibv_resp, sizeof(resp)))
> +                               &resp.ibv_resp, sizeof(resp)))
>                 goto err_free;
>
>         if (resp.kernel_ver != NES_ABI_KERNEL_VER) {
> @@ -135,12 +134,10 @@ static struct ibv_context *nes_ualloc_context(struct ibv_device *ibdev, int cmd_
>                         sscanf(value, "%d", &nes_drv_opt);
>         }
>
> -       nesvctx->ibv_ctx.device = ibdev;
> -
>         if (nes_drv_opt & NES_DRV_OPT_NO_DB_READ)
>                 nes_uctx_ops.poll_cq = nes_upoll_cq_no_db_read;
>
> -       nesvctx->ibv_ctx.ops = nes_uctx_ops;
> +       nesvctx->ibv_ctx.context.ops = nes_uctx_ops;
>         nesvctx->max_pds = resp.max_pds;
>         nesvctx->max_qps = resp.max_qps;
>         nesvctx->wq_size = resp.wq_size;
> @@ -148,16 +145,17 @@ static struct ibv_context *nes_ualloc_context(struct ibv_device *ibdev, int cmd_
>         nesvctx->mcrqf = 0;
>
>         /* Get a doorbell region for the CQs */
> -       ibv_pd = nes_ualloc_pd(&nesvctx->ibv_ctx);
> +       ibv_pd = nes_ualloc_pd(&nesvctx->ibv_ctx.context);
>         if (!ibv_pd)
>                 goto err_free;
> -       ibv_pd->context = &nesvctx->ibv_ctx;
> +       ibv_pd->context = &nesvctx->ibv_ctx.context;
>         nesvctx->nesupd = to_nes_upd(ibv_pd);
>
>         return &nesvctx->ibv_ctx;
>
>  err_free:
>         fprintf(stderr, PFX "%s: Failed to allocate context for device.\n", __FUNCTION__);
> +       verbs_uninit_context(&nesvctx->ibv_ctx);
>         free(nesvctx);
>
>         return NULL;
> @@ -172,6 +170,7 @@ static void nes_ufree_context(struct ibv_context *ibctx)
>         struct nes_uvcontext *nesvctx = to_nes_uctx(ibctx);
>         nes_ufree_pd(&nesvctx->nesupd->ibv_pd);
>
> +       verbs_uninit_context(&nesvctx->ibv_ctx);
>         free(nesvctx);
>  }
>
> diff --git a/providers/nes/nes_umain.h b/providers/nes/nes_umain.h
> index 0a832e7517bea6..2750c128d76ce7 100644
> --- a/providers/nes/nes_umain.h
> +++ b/providers/nes/nes_umain.h
> @@ -261,7 +261,7 @@ struct nes_upd {
>  };
>
>  struct nes_uvcontext {
> -       struct ibv_context ibv_ctx;
> +       struct verbs_context ibv_ctx;
>         struct nes_upd *nesupd;
>         uint32_t max_pds; /* maximum pds allowed for this user process */
>         uint32_t max_qps; /* maximum qps allowed for this user process */
> @@ -331,7 +331,7 @@ static inline struct nes_udevice *to_nes_udev(struct ibv_device *ibdev)
>
>  static inline struct nes_uvcontext *to_nes_uctx(struct ibv_context *ibctx)
>  {
> -       return to_nes_uxxx(ctx, vcontext);
> +       return container_of(ibctx, struct nes_uvcontext, ibv_ctx.context);
>  }
>
>  static inline struct nes_upd *to_nes_upd(struct ibv_pd *ibpd)
> diff --git a/providers/ocrdma/ocrdma_main.c b/providers/ocrdma/ocrdma_main.c
> index afd5d79c1884c0..5bb17eb8665bfc 100644
> --- a/providers/ocrdma/ocrdma_main.c
> +++ b/providers/ocrdma/ocrdma_main.c
> @@ -105,27 +105,23 @@ static void ocrdma_uninit_device(struct verbs_device *verbs_device)
>  /*
>   * ocrdma_alloc_context
>   */
> -static struct ibv_context *ocrdma_alloc_context(struct ibv_device *ibdev,
> -                                               int cmd_fd)
> +static struct verbs_context *ocrdma_alloc_context(struct ibv_device *ibdev,
> +                                                 int cmd_fd)
>  {
>         struct ocrdma_devctx *ctx;
>         struct ocrdma_get_context cmd;
>         struct ocrdma_alloc_ucontext_resp resp;
>
> -       ctx = calloc(1, sizeof(struct ocrdma_devctx));
> +       ctx = verbs_init_and_alloc_context(ibdev, cmd_fd, ctx, ibv_ctx);
>         if (!ctx)
>                 return NULL;
> -       memset(&resp, 0, sizeof(resp));
> -
> -       ctx->ibv_ctx.cmd_fd = cmd_fd;
>
>         if (ibv_cmd_get_context(&ctx->ibv_ctx,
>                                 (struct ibv_get_context *)&cmd, sizeof cmd,
>                                 &resp.ibv_resp, sizeof(resp)))
>                 goto cmd_err;
>
> -       ctx->ibv_ctx.device = ibdev;
> -       ctx->ibv_ctx.ops = ocrdma_ctx_ops;
> +       ctx->ibv_ctx.context.ops = ocrdma_ctx_ops;
>         get_ocrdma_dev(ibdev)->id = resp.dev_id;
>         get_ocrdma_dev(ibdev)->max_inline_data = resp.max_inline_data;
>         get_ocrdma_dev(ibdev)->wqe_size = resp.wqe_size;
> @@ -146,6 +142,7 @@ static struct ibv_context *ocrdma_alloc_context(struct ibv_device *ibdev,
>
>  cmd_err:
>         ocrdma_err("%s: Failed to allocate context for device.\n", __func__);
> +       verbs_uninit_context(&ctx->ibv_ctx);
>         free(ctx);
>         return NULL;
>  }
> @@ -160,6 +157,7 @@ static void ocrdma_free_context(struct ibv_context *ibctx)
>         if (ctx->ah_tbl)
>                 munmap((void *)ctx->ah_tbl, ctx->ah_tbl_len);
>
> +       verbs_uninit_context(&ctx->ibv_ctx);
>         free(ctx);
>  }
>
> diff --git a/providers/ocrdma/ocrdma_main.h b/providers/ocrdma/ocrdma_main.h
> index e5b2860f9dc45c..e414223d07cd83 100644
> --- a/providers/ocrdma/ocrdma_main.h
> +++ b/providers/ocrdma/ocrdma_main.h
> @@ -68,7 +68,7 @@ struct ocrdma_device {
>  };
>
>  struct ocrdma_devctx {
> -       struct ibv_context ibv_ctx;
> +       struct verbs_context ibv_ctx;
>         uint32_t *ah_tbl;
>         uint32_t ah_tbl_len;
>         pthread_mutex_t tbl_lock;
> @@ -231,7 +231,7 @@ struct ocrdma_ah {
>
>  static inline struct ocrdma_devctx *get_ocrdma_ctx(struct ibv_context *ibctx)
>  {
> -       return get_ocrdma_xxx(ctx, devctx);
> +       return container_of(ibctx, struct ocrdma_devctx, ibv_ctx.context);
>  }
>
>  static inline struct ocrdma_device *get_ocrdma_dev(struct ibv_device *ibdev)
> diff --git a/providers/qedr/qelr.h b/providers/qedr/qelr.h
> index b3faa0044137d8..faa8e99cfa0798 100644
> --- a/providers/qedr/qelr.h
> +++ b/providers/qedr/qelr.h
> @@ -118,7 +118,7 @@ struct qelr_device {
>  };
>
>  struct qelr_devctx {
> -       struct ibv_context      ibv_ctx;
> +       struct verbs_context    ibv_ctx;
>         FILE                    *dbg_fp;
>         void                    *db_addr;
>         uint64_t                db_pa;
> @@ -251,7 +251,7 @@ struct qelr_qp {
>
>  static inline struct qelr_devctx *get_qelr_ctx(struct ibv_context *ibctx)
>  {
> -       return container_of(ibctx, struct qelr_devctx, ibv_ctx);
> +       return container_of(ibctx, struct qelr_devctx, ibv_ctx.context);
>  }
>
>  static inline struct qelr_device *get_qelr_dev(struct ibv_device *ibdev)
> diff --git a/providers/qedr/qelr_main.c b/providers/qedr/qelr_main.c
> index 4d62442a58dcb7..92a635cdcfca94 100644
> --- a/providers/qedr/qelr_main.c
> +++ b/providers/qedr/qelr_main.c
> @@ -155,19 +155,18 @@ static void qelr_set_debug_mask(void)
>                 qelr_dp_module = atoi(env);
>  }
>
> -static struct ibv_context *qelr_alloc_context(struct ibv_device *ibdev,
> -                                             int cmd_fd)
> +static struct verbs_context *qelr_alloc_context(struct ibv_device *ibdev,
> +                                               int cmd_fd)
>  {
>         struct qelr_devctx *ctx;
>         struct qelr_get_context cmd;
>         struct qelr_alloc_ucontext_resp resp;
>
> -       ctx = calloc(1, sizeof(struct qelr_devctx));
> +       ctx = verbs_init_and_alloc_context(ibdev, cmd_fd, ctx, ibv_ctx);
>         if (!ctx)
>                 return NULL;
> -       memset(&resp, 0, sizeof(resp));
>
> -       ctx->ibv_ctx.cmd_fd = cmd_fd;
> +       memset(&resp, 0, sizeof(resp));
>
>         qelr_open_debug_file(ctx);
>         qelr_set_debug_mask();
> @@ -178,8 +177,7 @@ static struct ibv_context *qelr_alloc_context(struct ibv_device *ibdev,
>                 goto cmd_err;
>
>         ctx->kernel_page_size = sysconf(_SC_PAGESIZE);
> -       ctx->ibv_ctx.device = ibdev;
> -       ctx->ibv_ctx.ops = qelr_ctx_ops;
> +       ctx->ibv_ctx.context.ops = qelr_ctx_ops;
>         ctx->db_pa = resp.db_pa;
>         ctx->db_size = resp.db_size;
>         ctx->max_send_wr = resp.max_send_wr;
> @@ -205,6 +203,7 @@ static struct ibv_context *qelr_alloc_context(struct ibv_device *ibdev,
>  cmd_err:
>         qelr_err("%s: Failed to allocate context for device.\n", __func__);
>         qelr_close_debug_file(ctx);
> +       verbs_uninit_context(&ctx->ibv_ctx);
>         free(ctx);
>         return NULL;
>  }
> @@ -217,6 +216,7 @@ static void qelr_free_context(struct ibv_context *ibctx)
>                 munmap(ctx->db_addr, ctx->db_size);
>
>         qelr_close_debug_file(ctx);
> +       verbs_uninit_context(&ctx->ibv_ctx);
>         free(ctx);
>  }
>
> diff --git a/providers/qedr/qelr_verbs.c b/providers/qedr/qelr_verbs.c
> index 7db0fb3216dde9..5d7aeb37453c44 100644
> --- a/providers/qedr/qelr_verbs.c
> +++ b/providers/qedr/qelr_verbs.c
> @@ -887,7 +887,7 @@ static inline void qelr_init_dpm_info(struct qelr_devctx *cxt,
>         dpm->is_edpm = 0;
>
>         /* Currently dpm is not supported for iWARP */
> -       if (IS_IWARP(cxt->ibv_ctx.device))
> +       if (IS_IWARP(cxt->ibv_ctx.context.device))
>                 return;
>
>         if (qelr_chain_is_full(&qp->sq.chain) &&
> diff --git a/providers/rxe/rxe.c b/providers/rxe/rxe.c
> index 683ffaa2a8af9c..5cfdf1aac08a86 100644
> --- a/providers/rxe/rxe.c
> +++ b/providers/rxe/rxe.c
> @@ -858,29 +858,27 @@ static struct ibv_context_ops rxe_ctx_ops = {
>         .detach_mcast = ibv_cmd_detach_mcast
>  };
>
> -static struct ibv_context *rxe_alloc_context(struct ibv_device *ibdev,
> -                                            int cmd_fd)
> +static struct verbs_context *rxe_alloc_context(struct ibv_device *ibdev,
> +                                              int cmd_fd)
>  {
>         struct rxe_context *context;
>         struct ibv_get_context cmd;
>         struct ibv_get_context_resp resp;
>
> -       context = malloc(sizeof *context);
> +       context = verbs_init_and_alloc_context(ibdev, cmd_fd, context, ibv_ctx);
>         if (!context)
>                 return NULL;
>
> -       memset(context, 0, sizeof *context);
> -       context->ibv_ctx.cmd_fd = cmd_fd;
> -
>         if (ibv_cmd_get_context(&context->ibv_ctx, &cmd,
>                                 sizeof cmd, &resp, sizeof resp))
>                 goto out;
>
> -       context->ibv_ctx.ops = rxe_ctx_ops;
> +       context->ibv_ctx.context.ops = rxe_ctx_ops;
>
>         return &context->ibv_ctx;
>
>  out:
> +       verbs_uninit_context(&context->ibv_ctx);
>         free(context);
>         return NULL;
>  }
> @@ -889,6 +887,7 @@ static void rxe_free_context(struct ibv_context *ibctx)
>  {
>         struct rxe_context *context = to_rctx(ibctx);
>
> +       verbs_uninit_context(&context->ibv_ctx);
>         free(context);
>  }
>
> diff --git a/providers/rxe/rxe.h b/providers/rxe/rxe.h
> index 1f331662b2ba2d..3fc0436127e432 100644
> --- a/providers/rxe/rxe.h
> +++ b/providers/rxe/rxe.h
> @@ -54,7 +54,7 @@ struct rxe_device {
>  };
>
>  struct rxe_context {
> -       struct ibv_context      ibv_ctx;
> +       struct verbs_context    ibv_ctx;
>  };
>
>  struct rxe_cq {
> @@ -98,7 +98,7 @@ struct rxe_srq {
>
>  static inline struct rxe_context *to_rctx(struct ibv_context *ibctx)
>  {
> -       return to_rxxx(ctx, context);
> +       return container_of(ibctx, struct rxe_context, ibv_ctx.context);
>  }
>
>  static inline struct rxe_device *to_rdev(struct ibv_device *ibdev)
> diff --git a/providers/vmw_pvrdma/pvrdma.h b/providers/vmw_pvrdma/pvrdma.h
> index 3bcec1cb71d14d..58165cf434b721 100644
> --- a/providers/vmw_pvrdma/pvrdma.h
> +++ b/providers/vmw_pvrdma/pvrdma.h
> @@ -105,7 +105,7 @@ struct pvrdma_device {
>  };
>
>  struct pvrdma_context {
> -       struct ibv_context              ibv_ctx;
> +       struct verbs_context            ibv_ctx;
>         void                            *uar;
>         pthread_spinlock_t              uar_lock;
>         int                             max_qp_wr;
> @@ -201,7 +201,7 @@ static inline struct pvrdma_device *to_vdev(struct ibv_device *ibdev)
>
>  static inline struct pvrdma_context *to_vctx(struct ibv_context *ibctx)
>  {
> -       return container_of(ibctx, struct pvrdma_context, ibv_ctx);
> +       return container_of(ibctx, struct pvrdma_context, ibv_ctx.context);
>  }
>
>  static inline struct pvrdma_pd *to_vpd(struct ibv_pd *ibpd)
> diff --git a/providers/vmw_pvrdma/pvrdma_main.c b/providers/vmw_pvrdma/pvrdma_main.c
> index 17736cd0079036..08b1d4e6d34f07 100644
> --- a/providers/vmw_pvrdma/pvrdma_main.c
> +++ b/providers/vmw_pvrdma/pvrdma_main.c
> @@ -111,7 +111,7 @@ static int pvrdma_init_context_shared(struct pvrdma_context *context,
>         struct ibv_get_context cmd;
>         struct user_pvrdma_alloc_ucontext_resp resp;
>
> -       context->ibv_ctx.cmd_fd = cmd_fd;
> +       context->ibv_ctx.context.cmd_fd = cmd_fd;
>         if (ibv_cmd_get_context(&context->ibv_ctx, &cmd, sizeof(cmd),
>                                 &resp.ibv_resp, sizeof(resp)))
>                 return errno;
> @@ -129,7 +129,7 @@ static int pvrdma_init_context_shared(struct pvrdma_context *context,
>         }
>
>         pthread_spin_init(&context->uar_lock, PTHREAD_PROCESS_PRIVATE);
> -       context->ibv_ctx.ops = pvrdma_ctx_ops;
> +       context->ibv_ctx.context.ops = pvrdma_ctx_ops;
>
>         return 0;
>  }
> @@ -141,18 +141,17 @@ static void pvrdma_free_context_shared(struct pvrdma_context *context,
>         free(context->qp_tbl);
>  }
>
> -static struct ibv_context *pvrdma_alloc_context(struct ibv_device *ibdev,
> -                                               int cmd_fd)
> +static struct verbs_context *pvrdma_alloc_context(struct ibv_device *ibdev,
> +                                                 int cmd_fd)
>  {
>         struct pvrdma_context *context;
>
> -       context = malloc(sizeof(*context));
> +       context = verbs_init_and_alloc_context(ibdev, cmd_fd, context, ibv_ctx);
>         if (!context)
>                 return NULL;
>
> -       memset(context, 0, sizeof(*context));
> -
>         if (pvrdma_init_context_shared(context, ibdev, cmd_fd)) {
> +               verbs_uninit_context(&context->ibv_ctx);
>                 free(context);
>                 return NULL;
>         }
> @@ -165,6 +164,7 @@ static void pvrdma_free_context(struct ibv_context *ibctx)
>         struct pvrdma_context *context = to_vctx(ibctx);
>
>         pvrdma_free_context_shared(context, to_vdev(ibctx->device));
> +       verbs_uninit_context(&context->ibv_ctx);
>         free(context);
>  }
>
> --
> 2.15.1
>
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jason Gunthorpe Jan. 10, 2018, 5:34 p.m. UTC | #2
On Wed, Jan 10, 2018 at 11:16:20AM +0530, Devesh Sharma wrote:

> > +/*
> > + * Allocate and initialize a context structure. This is called to create the
> > + * driver wrapper, and context_offset is the number of bytes into the wrapper
> > + * structure where the verbs_context starts.
> > + */
> > +void *_verbs_init_and_alloc_context(struct ibv_device *device, int cmd_fd,
> > +                                   size_t alloc_size,
> > +                                   struct verbs_context *context_offset)
> > +{
> > +       void *drv_context;
> > +       struct verbs_context *context;
> > +
> > +       drv_context = calloc(1, alloc_size);
> > +       if (!drv_context) {
> > +               errno = ENOMEM;
> > +               close(cmd_fd);
> > +               return NULL;
> > +       }
> > +
> > +       context = (struct verbs_context *)((uint8_t *)drv_context +
> > +                                          (uintptr_t)context_offset);
> 
> A wrapper macro would do better here?

What would we call it? It is kinda of a reverse container of

Thing is, this is the only place that does this calculation and it is
intimately tied to the definition of the
verbs_init_and_alloc_context() macro, so it really is unique and
special to this function.

To elaborate on what is happening here..

The driver calls

        cntx = verbs_init_and_alloc_context(vdev, cmd_fd, cntx, ibvctx);

Where:
        struct bnxt_re_context *cntx;

And the name 'ibvctx' is like container_of, where it refers to the
struct member inside cntx:

struct bnxt_re_context {
        struct verbs_context ibvctx;

This allows the allocation function to both return the 'struct
bnxt_re_context' and find the 'struct verbs_context' where the driver
placed it.

The alternative here is to force the driver to put the verbs_context
at the start of the struct, then eliminate the context_offset entirely
and replace it with a static assert scheme.

Do you think that is nicer?

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Devesh Sharma Jan. 11, 2018, 5:44 p.m. UTC | #3
On Wed, Jan 10, 2018 at 11:04 PM, Jason Gunthorpe <jgg@mellanox.com> wrote:
> On Wed, Jan 10, 2018 at 11:16:20AM +0530, Devesh Sharma wrote:
>
>> > +/*
>> > + * Allocate and initialize a context structure. This is called to create the
>> > + * driver wrapper, and context_offset is the number of bytes into the wrapper
>> > + * structure where the verbs_context starts.
>> > + */
>> > +void *_verbs_init_and_alloc_context(struct ibv_device *device, int cmd_fd,
>> > +                                   size_t alloc_size,
>> > +                                   struct verbs_context *context_offset)
>> > +{
>> > +       void *drv_context;
>> > +       struct verbs_context *context;
>> > +
>> > +       drv_context = calloc(1, alloc_size);
>> > +       if (!drv_context) {
>> > +               errno = ENOMEM;
>> > +               close(cmd_fd);
>> > +               return NULL;
>> > +       }
>> > +
>> > +       context = (struct verbs_context *)((uint8_t *)drv_context +
>> > +                                          (uintptr_t)context_offset);
>>
>> A wrapper macro would do better here?
>
> What would we call it? It is kinda of a reverse container of
may be get_ibverbs_context()
>
> Thing is, this is the only place that does this calculation and it is
> intimately tied to the definition of the
> verbs_init_and_alloc_context() macro, so it really is unique and
> special to this function.

If that is the case I don't mind leaving this as it is, may be it
would look better from code readability point of view if we wrap it.
>
> To elaborate on what is happening here..
>
> The driver calls
>
>         cntx = verbs_init_and_alloc_context(vdev, cmd_fd, cntx, ibvctx);
>
> Where:
>         struct bnxt_re_context *cntx;
>
> And the name 'ibvctx' is like container_of, where it refers to the
> struct member inside cntx:
>
> struct bnxt_re_context {
>         struct verbs_context ibvctx;
>
> This allows the allocation function to both return the 'struct
> bnxt_re_context' and find the 'struct verbs_context' where the driver
> placed it.
>
> The alternative here is to force the driver to put the verbs_context
> at the start of the struct, then eliminate the context_offset entirely
> and replace it with a static assert scheme.
>
> Do you think that is nicer?
If there are no specific reasons to allow drivers to put this struct
anywhere in their defs,
then things could be simpler verb_context is placed in the beginning.
>
> Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jason Gunthorpe Jan. 11, 2018, 5:54 p.m. UTC | #4
On Thu, Jan 11, 2018 at 11:14:33PM +0530, Devesh Sharma wrote:
> On Wed, Jan 10, 2018 at 11:04 PM, Jason Gunthorpe <jgg@mellanox.com> wrote:
> > On Wed, Jan 10, 2018 at 11:16:20AM +0530, Devesh Sharma wrote:
> >
> >> > +/*
> >> > + * Allocate and initialize a context structure. This is called to create the
> >> > + * driver wrapper, and context_offset is the number of bytes into the wrapper
> >> > + * structure where the verbs_context starts.
> >> > + */
> >> > +void *_verbs_init_and_alloc_context(struct ibv_device *device, int cmd_fd,
> >> > +                                   size_t alloc_size,
> >> > +                                   struct verbs_context *context_offset)
> >> > +{
> >> > +       void *drv_context;
> >> > +       struct verbs_context *context;
> >> > +
> >> > +       drv_context = calloc(1, alloc_size);
> >> > +       if (!drv_context) {
> >> > +               errno = ENOMEM;
> >> > +               close(cmd_fd);
> >> > +               return NULL;
> >> > +       }
> >> > +
> >> > +       context = (struct verbs_context *)((uint8_t *)drv_context +
> >> > +                                          (uintptr_t)context_offset);
> >>
> >> A wrapper macro would do better here?

> > Thing is, this is the only place that does this calculation and it is
> > intimately tied to the definition of the
> > verbs_init_and_alloc_context() macro, so it really is unique and
> > special to this function.
> 
> If that is the case I don't mind leaving this as it is, may be it
> would look better from code readability point of view if we wrap it.

Maybe I should just embrace the Pointer-Arith gcc extension:

  context = drv_context + (uintptr_t)context_offset;

Have to check first how prevalent it is already in the code.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Devesh Sharma Jan. 12, 2018, 11:08 a.m. UTC | #5
On Thu, Jan 11, 2018 at 11:24 PM, Jason Gunthorpe <jgg@mellanox.com> wrote:
> On Thu, Jan 11, 2018 at 11:14:33PM +0530, Devesh Sharma wrote:
>> On Wed, Jan 10, 2018 at 11:04 PM, Jason Gunthorpe <jgg@mellanox.com> wrote:
>> > On Wed, Jan 10, 2018 at 11:16:20AM +0530, Devesh Sharma wrote:
>> >
>> >> > +/*
>> >> > + * Allocate and initialize a context structure. This is called to create the
>> >> > + * driver wrapper, and context_offset is the number of bytes into the wrapper
>> >> > + * structure where the verbs_context starts.
>> >> > + */
>> >> > +void *_verbs_init_and_alloc_context(struct ibv_device *device, int cmd_fd,
>> >> > +                                   size_t alloc_size,
>> >> > +                                   struct verbs_context *context_offset)
>> >> > +{
>> >> > +       void *drv_context;
>> >> > +       struct verbs_context *context;
>> >> > +
>> >> > +       drv_context = calloc(1, alloc_size);
>> >> > +       if (!drv_context) {
>> >> > +               errno = ENOMEM;
>> >> > +               close(cmd_fd);
>> >> > +               return NULL;
>> >> > +       }
>> >> > +
>> >> > +       context = (struct verbs_context *)((uint8_t *)drv_context +
>> >> > +                                          (uintptr_t)context_offset);
>> >>
>> >> A wrapper macro would do better here?
>
>> > Thing is, this is the only place that does this calculation and it is
>> > intimately tied to the definition of the
>> > verbs_init_and_alloc_context() macro, so it really is unique and
>> > special to this function.
>>
>> If that is the case I don't mind leaving this as it is, may be it
>> would look better from code readability point of view if we wrap it.
>
> Maybe I should just embrace the Pointer-Arith gcc extension:
>
>   context = drv_context + (uintptr_t)context_offset;
>
> Have to check first how prevalent it is already in the code.
>

Okay..

> Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/CMakeLists.txt b/CMakeLists.txt
index b1467317b68561..e8f4a948ad9610 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -52,7 +52,7 @@  set(PACKAGE_VERSION "17.0")
 # When this is changed the values in these files need changing too:
 #   debian/libibverbs1.symbols
 #   libibverbs/libibverbs.map
-set(IBVERBS_PABI_VERSION "16")
+set(IBVERBS_PABI_VERSION "17")
 set(IBVERBS_PROVIDER_SUFFIX "-rdmav${IBVERBS_PABI_VERSION}.so")
 
 #-------------------------
diff --git a/debian/libibverbs1.symbols b/debian/libibverbs1.symbols
index 2678fa6e98acf7..7c7659e434bc63 100644
--- a/debian/libibverbs1.symbols
+++ b/debian/libibverbs1.symbols
@@ -1,7 +1,7 @@ 
 libibverbs.so.1 libibverbs1 #MINVER#
  IBVERBS_1.0@IBVERBS_1.0 1.1.6
  IBVERBS_1.1@IBVERBS_1.1 1.1.6
- (symver)IBVERBS_PRIVATE_16 16
+ (symver)IBVERBS_PRIVATE_17 17
  ibv_ack_async_event@IBVERBS_1.0 1.1.6
  ibv_ack_async_event@IBVERBS_1.1 1.1.6
  ibv_ack_cq_events@IBVERBS_1.0 1.1.6
diff --git a/libibverbs/cmd.c b/libibverbs/cmd.c
index b957550ed6fbdb..bcec94f5b0ce72 100644
--- a/libibverbs/cmd.c
+++ b/libibverbs/cmd.c
@@ -44,22 +44,22 @@ 
 #include "ibverbs.h"
 #include <ccan/minmax.h>
 
-int ibv_cmd_get_context(struct ibv_context *context, struct ibv_get_context *cmd,
-			size_t cmd_size, struct ibv_get_context_resp *resp,
-			size_t resp_size)
+int ibv_cmd_get_context(struct verbs_context *context_ex,
+			struct ibv_get_context *cmd, size_t cmd_size,
+			struct ibv_get_context_resp *resp, size_t resp_size)
 {
 	if (abi_ver < IB_USER_VERBS_MIN_ABI_VERSION)
 		return ENOSYS;
 
 	IBV_INIT_CMD_RESP(cmd, cmd_size, GET_CONTEXT, resp, resp_size);
 
-	if (write(context->cmd_fd, cmd, cmd_size) != cmd_size)
+	if (write(context_ex->context.cmd_fd, cmd, cmd_size) != cmd_size)
 		return errno;
 
 	(void) VALGRIND_MAKE_MEM_DEFINED(resp, resp_size);
 
-	context->async_fd         = resp->async_fd;
-	context->num_comp_vectors = resp->num_comp_vectors;
+	context_ex->context.async_fd = resp->async_fd;
+	context_ex->context.num_comp_vectors = resp->num_comp_vectors;
 
 	return 0;
 }
diff --git a/libibverbs/device.c b/libibverbs/device.c
index 4fb759c6474ad7..e42e37bd0a1f8d 100644
--- a/libibverbs/device.c
+++ b/libibverbs/device.c
@@ -162,7 +162,8 @@  static struct ibv_cq_ex *
 __lib_ibv_create_cq_ex(struct ibv_context *context,
 		       struct ibv_cq_init_attr_ex *cq_attr)
 {
-	struct verbs_context *vctx = verbs_get_ctx(context);
+	struct verbs_context *vctx =
+		container_of(context, struct verbs_context, context);
 	struct ibv_cq_ex *cq;
 
 	if (cq_attr->wc_flags & ~IBV_CREATE_CQ_SUP_WC_FLAGS) {
@@ -179,14 +180,115 @@  __lib_ibv_create_cq_ex(struct ibv_context *context,
 	return cq;
 }
 
+/*
+ * Ownership of cmd_fd is transferred into this function, and it will either
+ * be released during the matching call to verbs_uninit_contxt or during the
+ * failure path of this function.
+ */
+int verbs_init_context(struct verbs_context *context_ex,
+		       struct ibv_device *device, int cmd_fd)
+{
+	struct ibv_context *context = &context_ex->context;
+
+	ibverbs_device_hold(device);
+
+	context->device = device;
+	context->cmd_fd = cmd_fd;
+	context->async_fd = -1;
+	pthread_mutex_init(&context->mutex, NULL);
+
+	context_ex->context.abi_compat = __VERBS_ABI_IS_EXTENDED;
+	context_ex->sz = sizeof(*context_ex);
+
+	/*
+	 * In order to maintain backward/forward binary compatibility
+	 * with apps compiled against libibverbs-1.1.8 that use the
+	 * flow steering addition, we need to set the two
+	 * ABI_placeholder entries to match the driver set flow
+	 * entries.  This is because apps compiled against
+	 * libibverbs-1.1.8 use an inline ibv_create_flow and
+	 * ibv_destroy_flow function that looks in the placeholder
+	 * spots for the proper entry points.  For apps compiled
+	 * against libibverbs-1.1.9 and later, the inline functions
+	 * will be looking in the right place.
+	 */
+	context_ex->ABI_placeholder1 =
+		(void (*)(void))context_ex->ibv_create_flow;
+	context_ex->ABI_placeholder2 =
+		(void (*)(void))context_ex->ibv_destroy_flow;
+
+	context_ex->priv = calloc(1, sizeof(context_ex->priv));
+	if (!context_ex->priv) {
+		errno = ENOMEM;
+		close(cmd_fd);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Allocate and initialize a context structure. This is called to create the
+ * driver wrapper, and context_offset is the number of bytes into the wrapper
+ * structure where the verbs_context starts.
+ */
+void *_verbs_init_and_alloc_context(struct ibv_device *device, int cmd_fd,
+				    size_t alloc_size,
+				    struct verbs_context *context_offset)
+{
+	void *drv_context;
+	struct verbs_context *context;
+
+	drv_context = calloc(1, alloc_size);
+	if (!drv_context) {
+		errno = ENOMEM;
+		close(cmd_fd);
+		return NULL;
+	}
+
+	context = (struct verbs_context *)((uint8_t *)drv_context +
+					   (uintptr_t)context_offset);
+
+	if (verbs_init_context(context, device, cmd_fd))
+		goto err_free;
+
+	return drv_context;
+
+err_free:
+	free(drv_context);
+	return NULL;
+}
+
+/* Use the init_context flow to create a verbs_context */
+static struct verbs_context *alloc_context(struct verbs_device *device,
+					   int cmd_fd)
+{
+	struct verbs_context *context;
+
+	context = _verbs_init_and_alloc_context(
+		&device->device, cmd_fd,
+		sizeof(*context) + device->size_of_context, NULL);
+	if (!context)
+		return NULL;
+
+	if (device->ops->init_context(device, &context->context, cmd_fd))
+		goto err_uninit;
+
+	return context;
+
+err_uninit:
+	verbs_uninit_context(context);
+	free(context);
+	return NULL;
+}
+
 LATEST_SYMVER_FUNC(ibv_open_device, 1_1, "IBVERBS_1.1",
 		   struct ibv_context *,
 		   struct ibv_device *device)
 {
 	struct verbs_device *verbs_device = verbs_get_device(device);
 	char *devpath;
-	int cmd_fd, ret;
-	struct ibv_context *context;
+	int cmd_fd;
 	struct verbs_context *context_ex;
 
 	if (asprintf(&devpath, "/dev/infiniband/%s", device->dev_name) < 0)
@@ -202,96 +304,50 @@  LATEST_SYMVER_FUNC(ibv_open_device, 1_1, "IBVERBS_1.1",
 	if (cmd_fd < 0)
 		return NULL;
 
-	if (!verbs_device->ops->init_context) {
-		context = verbs_device->ops->alloc_context(device, cmd_fd);
-		if (!context)
-			goto err;
-	} else {
-		struct verbs_ex_private *priv;
-
-		/* Library now allocates the context */
-		context_ex = calloc(1, sizeof(*context_ex) +
-				       verbs_device->size_of_context);
-		if (!context_ex) {
-			errno = ENOMEM;
-			goto err;
-		}
-
-		priv = calloc(1, sizeof(*priv));
-		if (!priv) {
-			errno = ENOMEM;
-			free(context_ex);
-			goto err;
-		}
-
-		context_ex->priv = priv;
-		context_ex->context.abi_compat  = __VERBS_ABI_IS_EXTENDED;
-		context_ex->sz = sizeof(*context_ex);
-
-		context = &context_ex->context;
-		ret = verbs_device->ops->init_context(verbs_device, context, cmd_fd);
-		if (ret)
-			goto verbs_err;
-		/*
-		 * In order to maintain backward/forward binary compatibility
-		 * with apps compiled against libibverbs-1.1.8 that use the
-		 * flow steering addition, we need to set the two
-		 * ABI_placeholder entries to match the driver set flow
-		 * entries.  This is because apps compiled against
-		 * libibverbs-1.1.8 use an inline ibv_create_flow and
-		 * ibv_destroy_flow function that looks in the placeholder
-		 * spots for the proper entry points.  For apps compiled
-		 * against libibverbs-1.1.9 and later, the inline functions
-		 * will be looking in the right place.
-		 */
-		context_ex->ABI_placeholder1 = (void (*)(void)) context_ex->ibv_create_flow;
-		context_ex->ABI_placeholder2 = (void (*)(void)) context_ex->ibv_destroy_flow;
-
-		if (context_ex->create_cq_ex) {
-			priv->create_cq_ex = context_ex->create_cq_ex;
-			context_ex->create_cq_ex = __lib_ibv_create_cq_ex;
-		}
-	}
+	if (!verbs_device->ops->init_context)
+		context_ex = verbs_device->ops->alloc_context(device, cmd_fd);
+	else
+		context_ex = alloc_context(verbs_device, cmd_fd);
 
-	context->device = device;
-	context->cmd_fd = cmd_fd;
-	pthread_mutex_init(&context->mutex, NULL);
+	/*
+	 * cmd_fd ownership is transferred into alloc_context, if it fails
+	 * then it closes cmd_fd and returns NULL
+	 */
+	if (context_ex == NULL)
+		return NULL;
 
-	ibverbs_device_hold(device);
+	if (context_ex->create_cq_ex) {
+		context_ex->priv->create_cq_ex = context_ex->create_cq_ex;
+		context_ex->create_cq_ex = __lib_ibv_create_cq_ex;
+	}
 
-	return context;
+	return &context_ex->context;
+}
 
-verbs_err:
+void verbs_uninit_context(struct verbs_context *context_ex)
+{
 	free(context_ex->priv);
-	free(context_ex);
-err:
-	close(cmd_fd);
-	return NULL;
+	close(context_ex->context.cmd_fd);
+	close(context_ex->context.async_fd);
+	ibverbs_device_put(context_ex->context.device);
 }
 
 LATEST_SYMVER_FUNC(ibv_close_device, 1_1, "IBVERBS_1.1",
 		   int,
 		   struct ibv_context *context)
 {
-	int async_fd = context->async_fd;
-	int cmd_fd   = context->cmd_fd;
-	struct verbs_context *context_ex;
 	struct verbs_device *verbs_device = verbs_get_device(context->device);
-	struct ibv_device *device = context->device;
 
-	context_ex = verbs_get_ctx(context);
-	if (context_ex) {
+	if (verbs_device->ops->uninit_context) {
+		struct verbs_context *context_ex =
+			container_of(context, struct verbs_context, context);
+
 		verbs_device->ops->uninit_context(verbs_device, context);
-		free(context_ex->priv);
-		free(context_ex);
+		verbs_uninit_context(context_ex);
 	} else {
 		verbs_device->ops->free_context(context);
 	}
 
-	close(async_fd);
-	close(cmd_fd);
-	ibverbs_device_put(device);
-
 	return 0;
 }
 
diff --git a/libibverbs/driver.h b/libibverbs/driver.h
index 4698ba4e609f34..809c4f5c8cdf39 100644
--- a/libibverbs/driver.h
+++ b/libibverbs/driver.h
@@ -153,8 +153,8 @@  struct verbs_device_ops {
 	bool (*match_device)(struct verbs_sysfs_dev *sysfs_dev);
 
 	/* Old interface, do not use in new code. */
-	struct ibv_context *(*alloc_context)(struct ibv_device *device,
-					     int cmd_fd);
+	struct verbs_context *(*alloc_context)(struct ibv_device *device,
+					       int cmd_fd);
 	void (*free_context)(struct ibv_context *context);
 
 	/* New interface */
@@ -205,13 +205,26 @@  void verbs_register_driver(const struct verbs_device_ops *ops);
 		verbs_register_driver(&drv);                                   \
 	}
 
+void *_verbs_init_and_alloc_context(struct ibv_device *device, int cmd_fd,
+				    size_t alloc_size,
+				    struct verbs_context *context_offset);
+
+#define verbs_init_and_alloc_context(ibdev, cmd_fd, drv_ctx_ptr, ctx_memb)     \
+	((typeof(drv_ctx_ptr))_verbs_init_and_alloc_context(                   \
+		ibdev, cmd_fd, sizeof(*drv_ctx_ptr),                           \
+		&((typeof(drv_ctx_ptr))NULL)->ctx_memb))
+
+int verbs_init_context(struct verbs_context *context_ex,
+		       struct ibv_device *device, int cmd_fd);
+void verbs_uninit_context(struct verbs_context *context);
+
 void verbs_init_cq(struct ibv_cq *cq, struct ibv_context *context,
 		       struct ibv_comp_channel *channel,
 		       void *cq_context);
 
-int ibv_cmd_get_context(struct ibv_context *context, struct ibv_get_context *cmd,
-			size_t cmd_size, struct ibv_get_context_resp *resp,
-			size_t resp_size);
+int ibv_cmd_get_context(struct verbs_context *context,
+			struct ibv_get_context *cmd, size_t cmd_size,
+			struct ibv_get_context_resp *resp, size_t resp_size);
 int ibv_cmd_query_device(struct ibv_context *context,
 			 struct ibv_device_attr *device_attr,
 			 uint64_t *raw_fw_ver,
diff --git a/libibverbs/libibverbs.map.in b/libibverbs/libibverbs.map.in
index 3f635a94b82d58..b787b051b4c381 100644
--- a/libibverbs/libibverbs.map.in
+++ b/libibverbs/libibverbs.map.in
@@ -113,6 +113,7 @@  IBVERBS_1.1 {
 IBVERBS_PRIVATE_@IBVERBS_PABI_VERSION@ {
 	global:
 		/* These historical symbols are now private to libibverbs */
+		_verbs_init_and_alloc_context;
 		ibv_cmd_alloc_mw;
 		ibv_cmd_alloc_pd;
 		ibv_cmd_attach_mcast;
@@ -162,6 +163,7 @@  IBVERBS_PRIVATE_@IBVERBS_PABI_VERSION@ {
 		ibv_query_gid_type;
 		ibv_register_driver;
 		verbs_register_driver_@IBVERBS_PABI_VERSION@;
+		verbs_uninit_context;
 		verbs_init_cq;
 		ibv_cmd_modify_cq;
 };
diff --git a/providers/bnxt_re/main.c b/providers/bnxt_re/main.c
index 998c9fe3313389..5e83f9d1c12f35 100644
--- a/providers/bnxt_re/main.c
+++ b/providers/bnxt_re/main.c
@@ -111,14 +111,15 @@  static int bnxt_re_init_context(struct verbs_device *vdev,
 	struct bnxt_re_cntx_resp resp;
 	struct bnxt_re_dev *dev;
 	struct bnxt_re_context *cntx;
+	struct verbs_context *verbs_ctx = verbs_get_ctx(ibvctx);
 
 	dev = to_bnxt_re_dev(&vdev->device);
 	cntx = to_bnxt_re_context(ibvctx);
 
 	memset(&resp, 0, sizeof(resp));
 	ibvctx->cmd_fd = cmd_fd;
-	if (ibv_cmd_get_context(ibvctx, &cmd, sizeof(cmd),
-				&resp.resp, sizeof(resp)))
+	if (ibv_cmd_get_context(verbs_ctx, &cmd, sizeof(cmd), &resp.resp,
+				sizeof(resp)))
 		return errno;
 
 	cntx->dev_id = resp.dev_id;
diff --git a/providers/cxgb3/iwch.c b/providers/cxgb3/iwch.c
index da9179fbbe2a8d..d4d5a96ffd524e 100644
--- a/providers/cxgb3/iwch.c
+++ b/providers/cxgb3/iwch.c
@@ -104,42 +104,38 @@  unsigned long iwch_page_size;
 unsigned long iwch_page_shift;
 unsigned long iwch_page_mask;
 
-static struct ibv_context *iwch_alloc_context(struct ibv_device *ibdev,
-					      int cmd_fd)
+static struct verbs_context *iwch_alloc_context(struct ibv_device *ibdev,
+						int cmd_fd)
 {
 	struct iwch_context *context;
 	struct ibv_get_context cmd;
 	struct iwch_alloc_ucontext_resp resp;
 	struct iwch_device *rhp = to_iwch_dev(ibdev);
 
-	context = malloc(sizeof *context);
+	context = verbs_init_and_alloc_context(ibdev, cmd_fd, context, ibv_ctx);
 	if (!context)
 		return NULL;
 
-	memset(context, 0, sizeof *context);
-	context->ibv_ctx.cmd_fd = cmd_fd;
-
 	if (ibv_cmd_get_context(&context->ibv_ctx, &cmd, sizeof cmd,
 				&resp.ibv_resp, sizeof resp))
 		goto err_free;
 
-	context->ibv_ctx.device = ibdev;
-	context->ibv_ctx.ops = iwch_ctx_ops;
+	context->ibv_ctx.context.ops = iwch_ctx_ops;
 
 	switch (rhp->hca_type) {
 	case CHELSIO_T3B:
 		PDBG("%s T3B device\n", __FUNCTION__);
-		context->ibv_ctx.ops.async_event = t3b_async_event;
-		context->ibv_ctx.ops.post_send = t3b_post_send;
-		context->ibv_ctx.ops.post_recv = t3b_post_recv;
-		context->ibv_ctx.ops.poll_cq = t3b_poll_cq;
+		context->ibv_ctx.context.ops.async_event = t3b_async_event;
+		context->ibv_ctx.context.ops.post_send = t3b_post_send;
+		context->ibv_ctx.context.ops.post_recv = t3b_post_recv;
+		context->ibv_ctx.context.ops.poll_cq = t3b_poll_cq;
 		break;
 	case CHELSIO_T3A:
 		PDBG("%s T3A device\n", __FUNCTION__);
-		context->ibv_ctx.ops.async_event = NULL;
-		context->ibv_ctx.ops.post_send = t3a_post_send;
-		context->ibv_ctx.ops.post_recv = t3a_post_recv;
-		context->ibv_ctx.ops.poll_cq = t3a_poll_cq;
+		context->ibv_ctx.context.ops.async_event = NULL;
+		context->ibv_ctx.context.ops.post_send = t3a_post_send;
+		context->ibv_ctx.context.ops.post_recv = t3a_post_recv;
+		context->ibv_ctx.context.ops.poll_cq = t3a_poll_cq;
 		break;
 	default:
 		PDBG("%s unknown hca type %d\n", __FUNCTION__, rhp->hca_type);
@@ -150,6 +146,7 @@  static struct ibv_context *iwch_alloc_context(struct ibv_device *ibdev,
 	return &context->ibv_ctx;
 
 err_free:
+	verbs_uninit_context(&context->ibv_ctx);
 	free(context);
 	return NULL;
 }
@@ -158,6 +155,7 @@  static void iwch_free_context(struct ibv_context *ibctx)
 {
 	struct iwch_context *context = to_iwch_ctx(ibctx);
 
+	verbs_uninit_context(&context->ibv_ctx);
 	free(context);
 }
 
diff --git a/providers/cxgb3/iwch.h b/providers/cxgb3/iwch.h
index 1b95fec664ef11..0b8060cf7cfa8f 100644
--- a/providers/cxgb3/iwch.h
+++ b/providers/cxgb3/iwch.h
@@ -71,7 +71,7 @@  static inline int t3a_device(struct iwch_device *dev)
 }
 
 struct iwch_context {
-	struct ibv_context ibv_ctx;
+	struct verbs_context ibv_ctx;
 };
 
 struct iwch_pd {
@@ -111,7 +111,7 @@  static inline struct iwch_device *to_iwch_dev(struct ibv_device *ibdev)
 
 static inline struct iwch_context *to_iwch_ctx(struct ibv_context *ibctx)
 {
-	return to_iwch_xxx(ctx, context);
+	return container_of(ibctx, struct iwch_context, ibv_ctx.context);
 }
 
 static inline struct iwch_pd *to_iwch_pd(struct ibv_pd *ibpd)
diff --git a/providers/cxgb4/dev.c b/providers/cxgb4/dev.c
index b6775da8afeef7..3c309d9f5defb5 100644
--- a/providers/cxgb4/dev.c
+++ b/providers/cxgb4/dev.c
@@ -96,8 +96,8 @@  static struct ibv_context_ops c4iw_ctx_ops = {
 	.req_notify_cq = c4iw_arm_cq,
 };
 
-static struct ibv_context *c4iw_alloc_context(struct ibv_device *ibdev,
-					      int cmd_fd)
+static struct verbs_context *c4iw_alloc_context(struct ibv_device *ibdev,
+						int cmd_fd)
 {
 	struct c4iw_context *context;
 	struct ibv_get_context cmd;
@@ -107,13 +107,10 @@  static struct ibv_context *c4iw_alloc_context(struct ibv_device *ibdev,
 	uint64_t raw_fw_ver;
 	struct ibv_device_attr attr;
 
-	context = malloc(sizeof *context);
+	context = verbs_init_and_alloc_context(ibdev, cmd_fd, context, ibv_ctx);
 	if (!context)
 		return NULL;
 
-	memset(context, 0, sizeof *context);
-	context->ibv_ctx.cmd_fd = cmd_fd;
-
 	resp.status_page_size = 0;
 	resp.reserved = 0;
 	if (ibv_cmd_get_context(&context->ibv_ctx, &cmd, sizeof cmd,
@@ -133,8 +130,7 @@  static struct ibv_context *c4iw_alloc_context(struct ibv_device *ibdev,
 			goto err_free;
 	} 
 
-	context->ibv_ctx.device = ibdev;
-	context->ibv_ctx.ops = c4iw_ctx_ops;
+	context->ibv_ctx.context.ops = c4iw_ctx_ops;
 
 	switch (rhp->chip_version) {
 	case CHELSIO_T6:
@@ -143,11 +139,11 @@  static struct ibv_context *c4iw_alloc_context(struct ibv_device *ibdev,
 		PDBG("%s T5/T4 device\n", __FUNCTION__);
 	case CHELSIO_T4:
 		PDBG("%s T4 device\n", __FUNCTION__);
-		context->ibv_ctx.ops.async_event = c4iw_async_event;
-		context->ibv_ctx.ops.post_send = c4iw_post_send;
-		context->ibv_ctx.ops.post_recv = c4iw_post_receive;
-		context->ibv_ctx.ops.poll_cq = c4iw_poll_cq;
-		context->ibv_ctx.ops.req_notify_cq = c4iw_arm_cq;
+		context->ibv_ctx.context.ops.async_event = c4iw_async_event;
+		context->ibv_ctx.context.ops.post_send = c4iw_post_send;
+		context->ibv_ctx.context.ops.post_recv = c4iw_post_receive;
+		context->ibv_ctx.context.ops.poll_cq = c4iw_poll_cq;
+		context->ibv_ctx.context.ops.req_notify_cq = c4iw_arm_cq;
 		break;
 	default:
 		PDBG("%s unknown hca type %d\n", __FUNCTION__,
@@ -159,8 +155,8 @@  static struct ibv_context *c4iw_alloc_context(struct ibv_device *ibdev,
 	if (!rhp->mmid2ptr) {
 		int ret;
 
-		ret = ibv_cmd_query_device(&context->ibv_ctx, &attr, &raw_fw_ver, &qcmd,
-					   sizeof qcmd);
+		ret = ibv_cmd_query_device(&context->ibv_ctx.context, &attr,
+					   &raw_fw_ver, &qcmd, sizeof(qcmd));
 		if (ret)
 			goto err_unmap;
 		rhp->max_mr = attr.max_mr;
@@ -201,6 +197,7 @@  err_free:
 		free(rhp->cqid2ptr);
 	if (rhp->mmid2ptr)
 		free(rhp->cqid2ptr);
+	verbs_uninit_context(&context->ibv_ctx);
 	free(context);
 	return NULL;
 }
@@ -211,6 +208,8 @@  static void c4iw_free_context(struct ibv_context *ibctx)
 
 	if (context->status_page_size)
 		munmap(context->status_page, context->status_page_size);
+
+	verbs_uninit_context(&context->ibv_ctx);
 	free(context);
 }
 
diff --git a/providers/cxgb4/libcxgb4.h b/providers/cxgb4/libcxgb4.h
index a5256f7e081770..893bd85d5f34b2 100644
--- a/providers/cxgb4/libcxgb4.h
+++ b/providers/cxgb4/libcxgb4.h
@@ -80,7 +80,7 @@  static inline int dev_is_t4(struct c4iw_dev *dev)
 }
 
 struct c4iw_context {
-	struct ibv_context ibv_ctx;
+	struct verbs_context ibv_ctx;
 	struct t4_dev_status_page *status_page;
 	int status_page_size;
 };
@@ -129,7 +129,7 @@  static inline struct c4iw_dev *to_c4iw_dev(struct ibv_device *ibdev)
 
 static inline struct c4iw_context *to_c4iw_context(struct ibv_context *ibctx)
 {
-	return to_c4iw_xxx(ctx, context);
+	return container_of(ibctx, struct c4iw_context, ibv_ctx.context);
 }
 
 static inline struct c4iw_pd *to_c4iw_pd(struct ibv_pd *ibpd)
diff --git a/providers/hfi1verbs/hfiverbs.c b/providers/hfi1verbs/hfiverbs.c
index 7f8f5714db1630..6117f99fbc27a2 100644
--- a/providers/hfi1verbs/hfiverbs.c
+++ b/providers/hfi1verbs/hfiverbs.c
@@ -123,41 +123,42 @@  static struct ibv_context_ops hfi1_ctx_ops = {
 	.detach_mcast	= ibv_cmd_detach_mcast
 };
 
-static struct ibv_context *hfi1_alloc_context(struct ibv_device *ibdev,
-					       int cmd_fd)
+static struct verbs_context *hfi1_alloc_context(struct ibv_device *ibdev,
+						int cmd_fd)
 {
 	struct hfi1_context	    *context;
 	struct ibv_get_context       cmd;
 	struct ibv_get_context_resp  resp;
 	struct hfi1_device         *dev;
 
-	context = malloc(sizeof *context);
+	context = verbs_init_and_alloc_context(ibdev, cmd_fd, context, ibv_ctx);
 	if (!context)
 		return NULL;
-	memset(context, 0, sizeof *context);
-	context->ibv_ctx.cmd_fd = cmd_fd;
+
 	if (ibv_cmd_get_context(&context->ibv_ctx, &cmd,
 				sizeof cmd, &resp, sizeof resp))
 		goto err_free;
 
-	context->ibv_ctx.ops = hfi1_ctx_ops;
+	context->ibv_ctx.context.ops = hfi1_ctx_ops;
 	dev = to_idev(ibdev);
 	if (dev->abi_version == 1) {
-		context->ibv_ctx.ops.create_cq     = hfi1_create_cq_v1;
-		context->ibv_ctx.ops.poll_cq       = ibv_cmd_poll_cq;
-		context->ibv_ctx.ops.resize_cq     = hfi1_resize_cq_v1;
-		context->ibv_ctx.ops.destroy_cq    = hfi1_destroy_cq_v1;
-		context->ibv_ctx.ops.create_srq    = hfi1_create_srq_v1;
-		context->ibv_ctx.ops.destroy_srq   = hfi1_destroy_srq_v1;
-		context->ibv_ctx.ops.modify_srq    = hfi1_modify_srq_v1;
-		context->ibv_ctx.ops.post_srq_recv = ibv_cmd_post_srq_recv;
-		context->ibv_ctx.ops.create_qp     = hfi1_create_qp_v1;
-		context->ibv_ctx.ops.destroy_qp    = hfi1_destroy_qp_v1;
-		context->ibv_ctx.ops.post_recv     = ibv_cmd_post_recv;
+		context->ibv_ctx.context.ops.create_cq = hfi1_create_cq_v1;
+		context->ibv_ctx.context.ops.poll_cq = ibv_cmd_poll_cq;
+		context->ibv_ctx.context.ops.resize_cq = hfi1_resize_cq_v1;
+		context->ibv_ctx.context.ops.destroy_cq = hfi1_destroy_cq_v1;
+		context->ibv_ctx.context.ops.create_srq = hfi1_create_srq_v1;
+		context->ibv_ctx.context.ops.destroy_srq = hfi1_destroy_srq_v1;
+		context->ibv_ctx.context.ops.modify_srq = hfi1_modify_srq_v1;
+		context->ibv_ctx.context.ops.post_srq_recv =
+			ibv_cmd_post_srq_recv;
+		context->ibv_ctx.context.ops.create_qp = hfi1_create_qp_v1;
+		context->ibv_ctx.context.ops.destroy_qp = hfi1_destroy_qp_v1;
+		context->ibv_ctx.context.ops.post_recv = ibv_cmd_post_recv;
 	}
 	return &context->ibv_ctx;
 
 err_free:
+	verbs_uninit_context(&context->ibv_ctx);
 	free(context);
 	return NULL;
 }
@@ -166,6 +167,7 @@  static void hfi1_free_context(struct ibv_context *ibctx)
 {
 	struct hfi1_context *context = to_ictx(ibctx);
 
+	verbs_uninit_context(&context->ibv_ctx);
 	free(context);
 }
 
diff --git a/providers/hfi1verbs/hfiverbs.h b/providers/hfi1verbs/hfiverbs.h
index e672dda4982527..e7a05a0c0a83db 100644
--- a/providers/hfi1verbs/hfiverbs.h
+++ b/providers/hfi1verbs/hfiverbs.h
@@ -74,7 +74,7 @@  struct hfi1_device {
 };
 
 struct hfi1_context {
-	struct ibv_context	ibv_ctx;
+	struct verbs_context	ibv_ctx;
 };
 
 /*
@@ -158,7 +158,7 @@  struct hfi1_srq {
 
 static inline struct hfi1_context *to_ictx(struct ibv_context *ibctx)
 {
-	return to_ixxx(ctx, context);
+	return container_of(ibctx, struct hfi1_context, ibv_ctx.context);
 }
 
 static inline struct hfi1_device *to_idev(struct ibv_device *ibdev)
diff --git a/providers/hns/hns_roce_u.c b/providers/hns/hns_roce_u.c
index 489b71614614fe..781825b3782044 100644
--- a/providers/hns/hns_roce_u.c
+++ b/providers/hns/hns_roce_u.c
@@ -61,8 +61,8 @@  static const struct verbs_match_ent hca_table[] = {
 	{}
 };
 
-static struct ibv_context *hns_roce_alloc_context(struct ibv_device *ibdev,
-						  int cmd_fd)
+static struct verbs_context *hns_roce_alloc_context(struct ibv_device *ibdev,
+						    int cmd_fd)
 {
 	int i;
 	struct ibv_get_context cmd;
@@ -71,11 +71,10 @@  static struct ibv_context *hns_roce_alloc_context(struct ibv_device *ibdev,
 	struct hns_roce_alloc_ucontext_resp resp;
 	struct hns_roce_device *hr_dev = to_hr_dev(ibdev);
 
-	context = calloc(1, sizeof(*context));
+	context = verbs_init_and_alloc_context(ibdev, cmd_fd, context, ibv_ctx);
 	if (!context)
 		return NULL;
 
-	context->ibv_ctx.cmd_fd = cmd_fd;
 	if (ibv_cmd_get_context(&context->ibv_ctx, &cmd, sizeof(cmd),
 				&resp.ibv_resp, sizeof(resp)))
 		goto err_free;
@@ -113,28 +112,28 @@  static struct ibv_context *hns_roce_alloc_context(struct ibv_device *ibdev,
 
 	pthread_spin_init(&context->uar_lock, PTHREAD_PROCESS_PRIVATE);
 
-	context->ibv_ctx.ops.query_device  = hns_roce_u_query_device;
-	context->ibv_ctx.ops.query_port    = hns_roce_u_query_port;
-	context->ibv_ctx.ops.alloc_pd	   = hns_roce_u_alloc_pd;
-	context->ibv_ctx.ops.dealloc_pd    = hns_roce_u_free_pd;
-	context->ibv_ctx.ops.reg_mr	   = hns_roce_u_reg_mr;
-	context->ibv_ctx.ops.rereg_mr	   = hns_roce_u_rereg_mr;
-	context->ibv_ctx.ops.dereg_mr	   = hns_roce_u_dereg_mr;
-
-	context->ibv_ctx.ops.create_cq     = hns_roce_u_create_cq;
-	context->ibv_ctx.ops.poll_cq	   = hr_dev->u_hw->poll_cq;
-	context->ibv_ctx.ops.req_notify_cq = hr_dev->u_hw->arm_cq;
-	context->ibv_ctx.ops.cq_event	   = hns_roce_u_cq_event;
-	context->ibv_ctx.ops.destroy_cq    = hns_roce_u_destroy_cq;
-
-	context->ibv_ctx.ops.create_qp     = hns_roce_u_create_qp;
-	context->ibv_ctx.ops.query_qp	   = hns_roce_u_query_qp;
-	context->ibv_ctx.ops.modify_qp     = hr_dev->u_hw->modify_qp;
-	context->ibv_ctx.ops.destroy_qp    = hr_dev->u_hw->destroy_qp;
-	context->ibv_ctx.ops.post_send     = hr_dev->u_hw->post_send;
-	context->ibv_ctx.ops.post_recv     = hr_dev->u_hw->post_recv;
-
-	if (hns_roce_u_query_device(&context->ibv_ctx, &dev_attrs))
+	context->ibv_ctx.context.ops.query_device  = hns_roce_u_query_device;
+	context->ibv_ctx.context.ops.query_port    = hns_roce_u_query_port;
+	context->ibv_ctx.context.ops.alloc_pd	   = hns_roce_u_alloc_pd;
+	context->ibv_ctx.context.ops.dealloc_pd    = hns_roce_u_free_pd;
+	context->ibv_ctx.context.ops.reg_mr	   = hns_roce_u_reg_mr;
+	context->ibv_ctx.context.ops.rereg_mr	   = hns_roce_u_rereg_mr;
+	context->ibv_ctx.context.ops.dereg_mr	   = hns_roce_u_dereg_mr;
+
+	context->ibv_ctx.context.ops.create_cq     = hns_roce_u_create_cq;
+	context->ibv_ctx.context.ops.poll_cq	   = hr_dev->u_hw->poll_cq;
+	context->ibv_ctx.context.ops.req_notify_cq = hr_dev->u_hw->arm_cq;
+	context->ibv_ctx.context.ops.cq_event	   = hns_roce_u_cq_event;
+	context->ibv_ctx.context.ops.destroy_cq    = hns_roce_u_destroy_cq;
+
+	context->ibv_ctx.context.ops.create_qp     = hns_roce_u_create_qp;
+	context->ibv_ctx.context.ops.query_qp	   = hns_roce_u_query_qp;
+	context->ibv_ctx.context.ops.modify_qp     = hr_dev->u_hw->modify_qp;
+	context->ibv_ctx.context.ops.destroy_qp    = hr_dev->u_hw->destroy_qp;
+	context->ibv_ctx.context.ops.post_send     = hr_dev->u_hw->post_send;
+	context->ibv_ctx.context.ops.post_recv     = hr_dev->u_hw->post_recv;
+
+	if (hns_roce_u_query_device(&context->ibv_ctx.context, &dev_attrs))
 		goto tptr_free;
 
 	context->max_qp_wr = dev_attrs.max_qp_wr;
@@ -155,6 +154,7 @@  db_free:
 	context->uar = NULL;
 
 err_free:
+	verbs_uninit_context(&context->ibv_ctx);
 	free(context);
 	return NULL;
 }
@@ -167,6 +167,7 @@  static void hns_roce_free_context(struct ibv_context *ibctx)
 	if (to_hr_dev(ibctx->device)->hw_version == HNS_ROCE_HW_VER1)
 		munmap(context->cq_tptr_base, HNS_ROCE_CQ_DB_BUF_SIZE);
 
+	verbs_uninit_context(&context->ibv_ctx);
 	free(context);
 }
 
diff --git a/providers/hns/hns_roce_u.h b/providers/hns/hns_roce_u.h
index 101320b1f8f3ad..02912468e68a65 100644
--- a/providers/hns/hns_roce_u.h
+++ b/providers/hns/hns_roce_u.h
@@ -94,7 +94,7 @@  struct hns_roce_buf {
 };
 
 struct hns_roce_context {
-	struct ibv_context		ibv_ctx;
+	struct verbs_context		ibv_ctx;
 	void				*uar;
 	pthread_spinlock_t		uar_lock;
 
@@ -221,7 +221,7 @@  static inline struct hns_roce_device *to_hr_dev(struct ibv_device *ibv_dev)
 
 static inline struct hns_roce_context *to_hr_ctx(struct ibv_context *ibv_ctx)
 {
-	return container_of(ibv_ctx, struct hns_roce_context, ibv_ctx);
+	return container_of(ibv_ctx, struct hns_roce_context, ibv_ctx.context);
 }
 
 static inline struct hns_roce_pd *to_hr_pd(struct ibv_pd *ibv_pd)
diff --git a/providers/hns/hns_roce_u_verbs.c b/providers/hns/hns_roce_u_verbs.c
index 046f0a4b849712..3def78d25a9a71 100644
--- a/providers/hns/hns_roce_u_verbs.c
+++ b/providers/hns/hns_roce_u_verbs.c
@@ -208,7 +208,8 @@  static void hns_roce_set_sq_sizes(struct hns_roce_qp *qp,
 
 static int hns_roce_verify_cq(int *cqe, struct hns_roce_context *context)
 {
-	struct hns_roce_device *hr_dev = to_hr_dev(context->ibv_ctx.device);
+	struct hns_roce_device *hr_dev =
+		to_hr_dev(context->ibv_ctx.context.device);
 
 	if (hr_dev->hw_version == HNS_ROCE_HW_VER1)
 		if (*cqe < HNS_ROCE_MIN_CQE_NUM) {
@@ -328,7 +329,8 @@  int hns_roce_u_destroy_cq(struct ibv_cq *cq)
 static int hns_roce_verify_qp(struct ibv_qp_init_attr *attr,
 			      struct hns_roce_context *context)
 {
-	struct hns_roce_device *hr_dev = to_hr_dev(context->ibv_ctx.device);
+	struct hns_roce_device *hr_dev =
+		to_hr_dev(context->ibv_ctx.context.device);
 
 	if (hr_dev->hw_version == HNS_ROCE_HW_VER1) {
 		if (attr->cap.max_send_wr < HNS_ROCE_MIN_WQE_NUM) {
diff --git a/providers/i40iw/i40iw_umain.c b/providers/i40iw/i40iw_umain.c
index 77c1ced812499b..6ec40895efcfe0 100644
--- a/providers/i40iw/i40iw_umain.c
+++ b/providers/i40iw/i40iw_umain.c
@@ -131,19 +131,18 @@  static struct ibv_context_ops i40iw_uctx_ops = {
  * context and getting back resource information to return as ibv_context.
  */
 
-static struct ibv_context *i40iw_ualloc_context(struct ibv_device *ibdev, int cmd_fd)
+static struct verbs_context *i40iw_ualloc_context(struct ibv_device *ibdev,
+						  int cmd_fd)
 {
 	struct ibv_pd *ibv_pd;
 	struct i40iw_uvcontext *iwvctx;
 	struct i40iw_get_context cmd;
 	struct i40iw_ualloc_ucontext_resp resp;
 
-	iwvctx = malloc(sizeof(*iwvctx));
+	iwvctx = verbs_init_and_alloc_context(ibdev, cmd_fd, iwvctx, ibv_ctx);
 	if (!iwvctx)
 		return NULL;
 
-	memset(iwvctx, 0, sizeof(*iwvctx));
-	iwvctx->ibv_ctx.cmd_fd = cmd_fd;
 	cmd.userspace_ver = I40IW_ABI_VER;
 	memset(&resp, 0, sizeof(resp));
 	if (ibv_cmd_get_context(&iwvctx->ibv_ctx, (struct ibv_get_context *)&cmd,
@@ -162,24 +161,24 @@  static struct ibv_context *i40iw_ualloc_context(struct ibv_device *ibdev, int cm
 		goto err_free;
 	}
 
-	iwvctx->ibv_ctx.device = ibdev;
-	iwvctx->ibv_ctx.ops = i40iw_uctx_ops;
+	iwvctx->ibv_ctx.context.ops = i40iw_uctx_ops;
 	iwvctx->max_pds = resp.max_pds;
 	iwvctx->max_qps = resp.max_qps;
 	iwvctx->wq_size = resp.wq_size;
 	iwvctx->abi_ver = resp.kernel_ver;
 
 	i40iw_device_init_uk(&iwvctx->dev);
-	ibv_pd = i40iw_ualloc_pd(&iwvctx->ibv_ctx);
+	ibv_pd = i40iw_ualloc_pd(&iwvctx->ibv_ctx.context);
 	if (!ibv_pd)
 		goto err_free;
-	ibv_pd->context = &iwvctx->ibv_ctx;
+	ibv_pd->context = &iwvctx->ibv_ctx.context;
 	iwvctx->iwupd = to_i40iw_upd(ibv_pd);
 
 	return &iwvctx->ibv_ctx;
 
 err_free:
 	fprintf(stderr, PFX "%s: failed to allocate context for device.\n", __func__);
+	verbs_uninit_context(&iwvctx->ibv_ctx);
 	free(iwvctx);
 
 	return NULL;
@@ -195,6 +194,7 @@  static void i40iw_ufree_context(struct ibv_context *ibctx)
 
 	i40iw_ufree_pd(&iwvctx->iwupd->ibv_pd);
 
+	verbs_uninit_context(&iwvctx->ibv_ctx);
 	free(iwvctx);
 }
 
diff --git a/providers/i40iw/i40iw_umain.h b/providers/i40iw/i40iw_umain.h
index 109aba6bd92ef4..a2f4fa8f6b6bd9 100644
--- a/providers/i40iw/i40iw_umain.h
+++ b/providers/i40iw/i40iw_umain.h
@@ -83,7 +83,7 @@  struct i40iw_upd {
 };
 
 struct i40iw_uvcontext {
-	struct ibv_context ibv_ctx;
+	struct verbs_context ibv_ctx;
 	struct i40iw_upd *iwupd;
 	uint32_t max_pds;	/* maximum pds allowed for this user process */
 	uint32_t max_qps;	/* maximum qps allowed for this user process */
@@ -137,7 +137,7 @@  static inline struct i40iw_udevice *to_i40iw_udev(struct ibv_device *ibdev)
 
 static inline struct i40iw_uvcontext *to_i40iw_uctx(struct ibv_context *ibctx)
 {
-	return to_i40iw_uxxx(ctx, vcontext);
+	return container_of(ibctx, struct i40iw_uvcontext, ibv_ctx.context);
 }
 
 static inline struct i40iw_upd *to_i40iw_upd(struct ibv_pd *ibpd)
diff --git a/providers/ipathverbs/ipathverbs.c b/providers/ipathverbs/ipathverbs.c
index 449abb0489955a..3f7f170ed6b986 100644
--- a/providers/ipathverbs/ipathverbs.c
+++ b/providers/ipathverbs/ipathverbs.c
@@ -122,41 +122,42 @@  static struct ibv_context_ops ipath_ctx_ops = {
 	.detach_mcast	= ibv_cmd_detach_mcast
 };
 
-static struct ibv_context *ipath_alloc_context(struct ibv_device *ibdev,
-					       int cmd_fd)
+static struct verbs_context *ipath_alloc_context(struct ibv_device *ibdev,
+						 int cmd_fd)
 {
 	struct ipath_context	    *context;
 	struct ibv_get_context       cmd;
 	struct ibv_get_context_resp  resp;
 	struct ipath_device         *dev;
 
-	context = malloc(sizeof *context);
+	context = verbs_init_and_alloc_context(ibdev, cmd_fd, context, ibv_ctx);
 	if (!context)
 		return NULL;
-	memset(context, 0, sizeof *context);
-	context->ibv_ctx.cmd_fd = cmd_fd;
+
 	if (ibv_cmd_get_context(&context->ibv_ctx, &cmd,
 				sizeof cmd, &resp, sizeof resp))
 		goto err_free;
 
-	context->ibv_ctx.ops = ipath_ctx_ops;
+	context->ibv_ctx.context.ops = ipath_ctx_ops;
 	dev = to_idev(ibdev);
 	if (dev->abi_version == 1) {
-		context->ibv_ctx.ops.create_cq     = ipath_create_cq_v1;
-		context->ibv_ctx.ops.poll_cq       = ibv_cmd_poll_cq;
-		context->ibv_ctx.ops.resize_cq     = ipath_resize_cq_v1;
-		context->ibv_ctx.ops.destroy_cq    = ipath_destroy_cq_v1;
-		context->ibv_ctx.ops.create_srq    = ipath_create_srq_v1;
-		context->ibv_ctx.ops.destroy_srq   = ipath_destroy_srq_v1;
-		context->ibv_ctx.ops.modify_srq    = ipath_modify_srq_v1;
-		context->ibv_ctx.ops.post_srq_recv = ibv_cmd_post_srq_recv;
-		context->ibv_ctx.ops.create_qp     = ipath_create_qp_v1;
-		context->ibv_ctx.ops.destroy_qp    = ipath_destroy_qp_v1;
-		context->ibv_ctx.ops.post_recv     = ibv_cmd_post_recv;
+		context->ibv_ctx.context.ops.create_cq = ipath_create_cq_v1;
+		context->ibv_ctx.context.ops.poll_cq = ibv_cmd_poll_cq;
+		context->ibv_ctx.context.ops.resize_cq = ipath_resize_cq_v1;
+		context->ibv_ctx.context.ops.destroy_cq = ipath_destroy_cq_v1;
+		context->ibv_ctx.context.ops.create_srq = ipath_create_srq_v1;
+		context->ibv_ctx.context.ops.destroy_srq = ipath_destroy_srq_v1;
+		context->ibv_ctx.context.ops.modify_srq = ipath_modify_srq_v1;
+		context->ibv_ctx.context.ops.post_srq_recv =
+			ibv_cmd_post_srq_recv;
+		context->ibv_ctx.context.ops.create_qp = ipath_create_qp_v1;
+		context->ibv_ctx.context.ops.destroy_qp = ipath_destroy_qp_v1;
+		context->ibv_ctx.context.ops.post_recv = ibv_cmd_post_recv;
 	}
 	return &context->ibv_ctx;
 
 err_free:
+	verbs_uninit_context(&context->ibv_ctx);
 	free(context);
 	return NULL;
 }
@@ -165,6 +166,7 @@  static void ipath_free_context(struct ibv_context *ibctx)
 {
 	struct ipath_context *context = to_ictx(ibctx);
 
+	verbs_uninit_context(&context->ibv_ctx);
 	free(context);
 }
 
diff --git a/providers/ipathverbs/ipathverbs.h b/providers/ipathverbs/ipathverbs.h
index 5f2658e7942c8b..d26a2a1b29009e 100644
--- a/providers/ipathverbs/ipathverbs.h
+++ b/providers/ipathverbs/ipathverbs.h
@@ -54,7 +54,7 @@  struct ipath_device {
 };
 
 struct ipath_context {
-	struct ibv_context	ibv_ctx;
+	struct verbs_context	ibv_ctx;
 };
 
 /*
@@ -137,7 +137,7 @@  struct ipath_srq {
 
 static inline struct ipath_context *to_ictx(struct ibv_context *ibctx)
 {
-	return to_ixxx(ctx, context);
+	return container_of(ibctx, struct ipath_context, ibv_ctx.context);
 }
 
 static inline struct ipath_device *to_idev(struct ibv_device *ibdev)
diff --git a/providers/mlx4/mlx4.c b/providers/mlx4/mlx4.c
index d2ccd328625c80..56bf1298b48734 100644
--- a/providers/mlx4/mlx4.c
+++ b/providers/mlx4/mlx4.c
@@ -167,16 +167,16 @@  static int mlx4_init_context(struct verbs_device *v_device,
 
 	mlx4_read_env();
 	if (dev->abi_version <= MLX4_UVERBS_NO_DEV_CAPS_ABI_VERSION) {
-		if (ibv_cmd_get_context(ibv_ctx, &cmd, sizeof cmd,
-					&resp_v3.ibv_resp, sizeof resp_v3))
+		if (ibv_cmd_get_context(verbs_ctx, &cmd, sizeof(cmd),
+					&resp_v3.ibv_resp, sizeof(resp_v3)))
 			return errno;
 
 		context->num_qps  = resp_v3.qp_tab_size;
 		bf_reg_size	  = resp_v3.bf_reg_size;
 		context->cqe_size = sizeof (struct mlx4_cqe);
 	} else  {
-		if (ibv_cmd_get_context(ibv_ctx, &cmd, sizeof cmd,
-					&resp.ibv_resp, sizeof resp))
+		if (ibv_cmd_get_context(verbs_ctx, &cmd, sizeof(cmd),
+					&resp.ibv_resp, sizeof(resp)))
 			return errno;
 
 		context->num_qps  = resp.qp_tab_size;
diff --git a/providers/mlx5/mlx5.c b/providers/mlx5/mlx5.c
index 36486218e31d81..a829cd5eb26473 100644
--- a/providers/mlx5/mlx5.c
+++ b/providers/mlx5/mlx5.c
@@ -549,7 +549,9 @@  static int mlx5_cmd_get_context(struct mlx5_context *context,
 				struct mlx5_alloc_ucontext_resp *resp,
 				size_t resp_len)
 {
-	if (!ibv_cmd_get_context(&context->ibv_ctx, &req->ibv_req,
+	struct verbs_context *verbs_ctx = verbs_get_ctx(&context->ibv_ctx);
+
+	if (!ibv_cmd_get_context(verbs_ctx, &req->ibv_req,
 				 req_len, &resp->ibv_resp, resp_len))
 		return 0;
 
@@ -572,12 +574,12 @@  static int mlx5_cmd_get_context(struct mlx5_context *context,
 	 * to do so. If zero is a valid response, we will add a new
 	 * field that indicates whether the request was handled.
 	 */
-	if (!ibv_cmd_get_context(&context->ibv_ctx, &req->ibv_req,
+	if (!ibv_cmd_get_context(verbs_ctx, &req->ibv_req,
 				 offsetof(struct mlx5_alloc_ucontext, lib_caps),
 				 &resp->ibv_resp, resp_len))
 		return 0;
 
-	return ibv_cmd_get_context(&context->ibv_ctx, &req->ibv_req,
+	return ibv_cmd_get_context(verbs_ctx, &req->ibv_req,
 				   offsetof(struct mlx5_alloc_ucontext,
 					    cqe_version),
 				   &resp->ibv_resp, resp_len);
diff --git a/providers/mthca/mthca.c b/providers/mthca/mthca.c
index 511b8d5139af9c..15827391986d3a 100644
--- a/providers/mthca/mthca.c
+++ b/providers/mthca/mthca.c
@@ -114,19 +114,18 @@  static struct ibv_context_ops mthca_ctx_ops = {
 	.detach_mcast  = ibv_cmd_detach_mcast
 };
 
-static struct ibv_context *mthca_alloc_context(struct ibv_device *ibdev, int cmd_fd)
+static struct verbs_context *mthca_alloc_context(struct ibv_device *ibdev,
+						 int cmd_fd)
 {
 	struct mthca_context            *context;
 	struct ibv_get_context           cmd;
 	struct mthca_alloc_ucontext_resp resp;
 	int                              i;
 
-	context = calloc(1, sizeof *context);
+	context = verbs_init_and_alloc_context(ibdev, cmd_fd, context, ibv_ctx);
 	if (!context)
 		return NULL;
 
-	context->ibv_ctx.cmd_fd = cmd_fd;
-
 	if (ibv_cmd_get_context(&context->ibv_ctx, &cmd, sizeof cmd,
 				&resp.ibv_resp, sizeof resp))
 		goto err_free;
@@ -135,13 +134,7 @@  static struct ibv_context *mthca_alloc_context(struct ibv_device *ibdev, int cmd
 	context->qp_table_shift = ffs(context->num_qps) - 1 - MTHCA_QP_TABLE_BITS;
 	context->qp_table_mask  = (1 << context->qp_table_shift) - 1;
 
-	/*
-	 * Need to set ibv_ctx.device because mthca_is_memfree() will
-	 * look at it to figure out the HCA type.
-	 */
-	context->ibv_ctx.device = ibdev;
-
-	if (mthca_is_memfree(&context->ibv_ctx)) {
+	if (mthca_is_memfree(&context->ibv_ctx.context)) {
 		context->db_tab = mthca_alloc_db_tab(resp.uarc_size);
 		if (!context->db_tab)
 			goto err_free;
@@ -159,26 +152,28 @@  static struct ibv_context *mthca_alloc_context(struct ibv_device *ibdev, int cmd
 
 	pthread_spin_init(&context->uar_lock, PTHREAD_PROCESS_PRIVATE);
 
-	context->pd = mthca_alloc_pd(&context->ibv_ctx);
+	context->pd = mthca_alloc_pd(&context->ibv_ctx.context);
 	if (!context->pd)
 		goto err_unmap;
 
-	context->pd->context = &context->ibv_ctx;
+	context->pd->context = &context->ibv_ctx.context;
 
-	context->ibv_ctx.ops = mthca_ctx_ops;
+	context->ibv_ctx.context.ops = mthca_ctx_ops;
 
-	if (mthca_is_memfree(&context->ibv_ctx)) {
-		context->ibv_ctx.ops.req_notify_cq = mthca_arbel_arm_cq;
-		context->ibv_ctx.ops.cq_event      = mthca_arbel_cq_event;
-		context->ibv_ctx.ops.post_send     = mthca_arbel_post_send;
-		context->ibv_ctx.ops.post_recv     = mthca_arbel_post_recv;
-		context->ibv_ctx.ops.post_srq_recv = mthca_arbel_post_srq_recv;
+	if (mthca_is_memfree(&context->ibv_ctx.context)) {
+		context->ibv_ctx.context.ops.req_notify_cq = mthca_arbel_arm_cq;
+		context->ibv_ctx.context.ops.cq_event = mthca_arbel_cq_event;
+		context->ibv_ctx.context.ops.post_send = mthca_arbel_post_send;
+		context->ibv_ctx.context.ops.post_recv = mthca_arbel_post_recv;
+		context->ibv_ctx.context.ops.post_srq_recv =
+			mthca_arbel_post_srq_recv;
 	} else {
-		context->ibv_ctx.ops.req_notify_cq = mthca_tavor_arm_cq;
-		context->ibv_ctx.ops.cq_event      = NULL;
-		context->ibv_ctx.ops.post_send     = mthca_tavor_post_send;
-		context->ibv_ctx.ops.post_recv     = mthca_tavor_post_recv;
-		context->ibv_ctx.ops.post_srq_recv = mthca_tavor_post_srq_recv;
+		context->ibv_ctx.context.ops.req_notify_cq = mthca_tavor_arm_cq;
+		context->ibv_ctx.context.ops.cq_event = NULL;
+		context->ibv_ctx.context.ops.post_send = mthca_tavor_post_send;
+		context->ibv_ctx.context.ops.post_recv = mthca_tavor_post_recv;
+		context->ibv_ctx.context.ops.post_srq_recv =
+			mthca_tavor_post_srq_recv;
 	}
 
 	return &context->ibv_ctx;
@@ -190,6 +185,7 @@  err_db_tab:
 	mthca_free_db_tab(context->db_tab);
 
 err_free:
+	verbs_uninit_context(&context->ibv_ctx);
 	free(context);
 	return NULL;
 }
@@ -201,6 +197,8 @@  static void mthca_free_context(struct ibv_context *ibctx)
 	mthca_free_pd(context->pd);
 	munmap(context->uar, to_mdev(ibctx->device)->page_size);
 	mthca_free_db_tab(context->db_tab);
+
+	verbs_uninit_context(&context->ibv_ctx);
 	free(context);
 }
 
diff --git a/providers/mthca/mthca.h b/providers/mthca/mthca.h
index a67acf46c7c56d..d788f7613b439c 100644
--- a/providers/mthca/mthca.h
+++ b/providers/mthca/mthca.h
@@ -97,7 +97,7 @@  struct mthca_device {
 struct mthca_db_table;
 
 struct mthca_context {
-	struct ibv_context     ibv_ctx;
+	struct verbs_context     ibv_ctx;
 	void                  *uar;
 	pthread_spinlock_t     uar_lock;
 	struct mthca_db_table *db_tab;
@@ -229,7 +229,7 @@  static inline struct mthca_device *to_mdev(struct ibv_device *ibdev)
 
 static inline struct mthca_context *to_mctx(struct ibv_context *ibctx)
 {
-	return to_mxxx(ctx, context);
+	return container_of(ibctx, struct mthca_context, ibv_ctx.context);
 }
 
 static inline struct mthca_pd *to_mpd(struct ibv_pd *ibpd)
diff --git a/providers/nes/nes_umain.c b/providers/nes/nes_umain.c
index bd0b6ac68cec40..a5ae678ecfe11c 100644
--- a/providers/nes/nes_umain.c
+++ b/providers/nes/nes_umain.c
@@ -98,7 +98,8 @@  static struct ibv_context_ops nes_uctx_ops = {
 /**
  * nes_ualloc_context
  */
-static struct ibv_context *nes_ualloc_context(struct ibv_device *ibdev, int cmd_fd)
+static struct verbs_context *nes_ualloc_context(struct ibv_device *ibdev,
+						int cmd_fd)
 {
 	struct ibv_pd *ibv_pd;
 	struct nes_uvcontext *nesvctx;
@@ -109,16 +110,14 @@  static struct ibv_context *nes_ualloc_context(struct ibv_device *ibdev, int cmd_
 
 	page_size = sysconf(_SC_PAGESIZE);
 
-	nesvctx = malloc(sizeof *nesvctx);
+	nesvctx = verbs_init_and_alloc_context(ibdev, cmd_fd, nesvctx, ibv_ctx);
 	if (!nesvctx)
 		return NULL;
 
-	memset(nesvctx, 0, sizeof *nesvctx);
-	nesvctx->ibv_ctx.cmd_fd = cmd_fd;
 	cmd.userspace_ver = NES_ABI_USERSPACE_VER;
 
 	if (ibv_cmd_get_context(&nesvctx->ibv_ctx, (struct ibv_get_context *)&cmd, sizeof cmd,
-			&resp.ibv_resp, sizeof(resp)))
+				&resp.ibv_resp, sizeof(resp)))
 		goto err_free;
 
 	if (resp.kernel_ver != NES_ABI_KERNEL_VER) {
@@ -135,12 +134,10 @@  static struct ibv_context *nes_ualloc_context(struct ibv_device *ibdev, int cmd_
 			sscanf(value, "%d", &nes_drv_opt);
 	}
 
-	nesvctx->ibv_ctx.device = ibdev;
-
 	if (nes_drv_opt & NES_DRV_OPT_NO_DB_READ)
 		nes_uctx_ops.poll_cq = nes_upoll_cq_no_db_read;
 
-	nesvctx->ibv_ctx.ops = nes_uctx_ops;
+	nesvctx->ibv_ctx.context.ops = nes_uctx_ops;
 	nesvctx->max_pds = resp.max_pds;
 	nesvctx->max_qps = resp.max_qps;
 	nesvctx->wq_size = resp.wq_size;
@@ -148,16 +145,17 @@  static struct ibv_context *nes_ualloc_context(struct ibv_device *ibdev, int cmd_
 	nesvctx->mcrqf = 0;
 
 	/* Get a doorbell region for the CQs */
-	ibv_pd = nes_ualloc_pd(&nesvctx->ibv_ctx);
+	ibv_pd = nes_ualloc_pd(&nesvctx->ibv_ctx.context);
 	if (!ibv_pd)
 		goto err_free;
-	ibv_pd->context = &nesvctx->ibv_ctx;
+	ibv_pd->context = &nesvctx->ibv_ctx.context;
 	nesvctx->nesupd = to_nes_upd(ibv_pd);
 
 	return &nesvctx->ibv_ctx;
 
 err_free:
  	fprintf(stderr, PFX "%s: Failed to allocate context for device.\n", __FUNCTION__);
+	verbs_uninit_context(&nesvctx->ibv_ctx);
 	free(nesvctx);
 
 	return NULL;
@@ -172,6 +170,7 @@  static void nes_ufree_context(struct ibv_context *ibctx)
 	struct nes_uvcontext *nesvctx = to_nes_uctx(ibctx);
 	nes_ufree_pd(&nesvctx->nesupd->ibv_pd);
 
+	verbs_uninit_context(&nesvctx->ibv_ctx);
 	free(nesvctx);
 }
 
diff --git a/providers/nes/nes_umain.h b/providers/nes/nes_umain.h
index 0a832e7517bea6..2750c128d76ce7 100644
--- a/providers/nes/nes_umain.h
+++ b/providers/nes/nes_umain.h
@@ -261,7 +261,7 @@  struct nes_upd {
 };
 
 struct nes_uvcontext {
-	struct ibv_context ibv_ctx;
+	struct verbs_context ibv_ctx;
 	struct nes_upd *nesupd;
 	uint32_t max_pds; /* maximum pds allowed for this user process */
 	uint32_t max_qps; /* maximum qps allowed for this user process */
@@ -331,7 +331,7 @@  static inline struct nes_udevice *to_nes_udev(struct ibv_device *ibdev)
 
 static inline struct nes_uvcontext *to_nes_uctx(struct ibv_context *ibctx)
 {
-	return to_nes_uxxx(ctx, vcontext);
+	return container_of(ibctx, struct nes_uvcontext, ibv_ctx.context);
 }
 
 static inline struct nes_upd *to_nes_upd(struct ibv_pd *ibpd)
diff --git a/providers/ocrdma/ocrdma_main.c b/providers/ocrdma/ocrdma_main.c
index afd5d79c1884c0..5bb17eb8665bfc 100644
--- a/providers/ocrdma/ocrdma_main.c
+++ b/providers/ocrdma/ocrdma_main.c
@@ -105,27 +105,23 @@  static void ocrdma_uninit_device(struct verbs_device *verbs_device)
 /*
  * ocrdma_alloc_context
  */
-static struct ibv_context *ocrdma_alloc_context(struct ibv_device *ibdev,
-						int cmd_fd)
+static struct verbs_context *ocrdma_alloc_context(struct ibv_device *ibdev,
+						  int cmd_fd)
 {
 	struct ocrdma_devctx *ctx;
 	struct ocrdma_get_context cmd;
 	struct ocrdma_alloc_ucontext_resp resp;
 
-	ctx = calloc(1, sizeof(struct ocrdma_devctx));
+	ctx = verbs_init_and_alloc_context(ibdev, cmd_fd, ctx, ibv_ctx);
 	if (!ctx)
 		return NULL;
-	memset(&resp, 0, sizeof(resp));
-
-	ctx->ibv_ctx.cmd_fd = cmd_fd;
 
 	if (ibv_cmd_get_context(&ctx->ibv_ctx,
 				(struct ibv_get_context *)&cmd, sizeof cmd,
 				&resp.ibv_resp, sizeof(resp)))
 		goto cmd_err;
 
-	ctx->ibv_ctx.device = ibdev;
-	ctx->ibv_ctx.ops = ocrdma_ctx_ops;
+	ctx->ibv_ctx.context.ops = ocrdma_ctx_ops;
 	get_ocrdma_dev(ibdev)->id = resp.dev_id;
 	get_ocrdma_dev(ibdev)->max_inline_data = resp.max_inline_data;
 	get_ocrdma_dev(ibdev)->wqe_size = resp.wqe_size;
@@ -146,6 +142,7 @@  static struct ibv_context *ocrdma_alloc_context(struct ibv_device *ibdev,
 
 cmd_err:
 	ocrdma_err("%s: Failed to allocate context for device.\n", __func__);
+	verbs_uninit_context(&ctx->ibv_ctx);
 	free(ctx);
 	return NULL;
 }
@@ -160,6 +157,7 @@  static void ocrdma_free_context(struct ibv_context *ibctx)
 	if (ctx->ah_tbl)
 		munmap((void *)ctx->ah_tbl, ctx->ah_tbl_len);
 
+	verbs_uninit_context(&ctx->ibv_ctx);
 	free(ctx);
 }
 
diff --git a/providers/ocrdma/ocrdma_main.h b/providers/ocrdma/ocrdma_main.h
index e5b2860f9dc45c..e414223d07cd83 100644
--- a/providers/ocrdma/ocrdma_main.h
+++ b/providers/ocrdma/ocrdma_main.h
@@ -68,7 +68,7 @@  struct ocrdma_device {
 };
 
 struct ocrdma_devctx {
-	struct ibv_context ibv_ctx;
+	struct verbs_context ibv_ctx;
 	uint32_t *ah_tbl;
 	uint32_t ah_tbl_len;
 	pthread_mutex_t tbl_lock;
@@ -231,7 +231,7 @@  struct ocrdma_ah {
 
 static inline struct ocrdma_devctx *get_ocrdma_ctx(struct ibv_context *ibctx)
 {
-	return get_ocrdma_xxx(ctx, devctx);
+	return container_of(ibctx, struct ocrdma_devctx, ibv_ctx.context);
 }
 
 static inline struct ocrdma_device *get_ocrdma_dev(struct ibv_device *ibdev)
diff --git a/providers/qedr/qelr.h b/providers/qedr/qelr.h
index b3faa0044137d8..faa8e99cfa0798 100644
--- a/providers/qedr/qelr.h
+++ b/providers/qedr/qelr.h
@@ -118,7 +118,7 @@  struct qelr_device {
 };
 
 struct qelr_devctx {
-	struct ibv_context	ibv_ctx;
+	struct verbs_context	ibv_ctx;
 	FILE			*dbg_fp;
 	void			*db_addr;
 	uint64_t		db_pa;
@@ -251,7 +251,7 @@  struct qelr_qp {
 
 static inline struct qelr_devctx *get_qelr_ctx(struct ibv_context *ibctx)
 {
-	return container_of(ibctx, struct qelr_devctx, ibv_ctx);
+	return container_of(ibctx, struct qelr_devctx, ibv_ctx.context);
 }
 
 static inline struct qelr_device *get_qelr_dev(struct ibv_device *ibdev)
diff --git a/providers/qedr/qelr_main.c b/providers/qedr/qelr_main.c
index 4d62442a58dcb7..92a635cdcfca94 100644
--- a/providers/qedr/qelr_main.c
+++ b/providers/qedr/qelr_main.c
@@ -155,19 +155,18 @@  static void qelr_set_debug_mask(void)
 		qelr_dp_module = atoi(env);
 }
 
-static struct ibv_context *qelr_alloc_context(struct ibv_device *ibdev,
-					      int cmd_fd)
+static struct verbs_context *qelr_alloc_context(struct ibv_device *ibdev,
+						int cmd_fd)
 {
 	struct qelr_devctx *ctx;
 	struct qelr_get_context cmd;
 	struct qelr_alloc_ucontext_resp resp;
 
-	ctx = calloc(1, sizeof(struct qelr_devctx));
+	ctx = verbs_init_and_alloc_context(ibdev, cmd_fd, ctx, ibv_ctx);
 	if (!ctx)
 		return NULL;
-	memset(&resp, 0, sizeof(resp));
 
-	ctx->ibv_ctx.cmd_fd = cmd_fd;
+	memset(&resp, 0, sizeof(resp));
 
 	qelr_open_debug_file(ctx);
 	qelr_set_debug_mask();
@@ -178,8 +177,7 @@  static struct ibv_context *qelr_alloc_context(struct ibv_device *ibdev,
 		goto cmd_err;
 
 	ctx->kernel_page_size = sysconf(_SC_PAGESIZE);
-	ctx->ibv_ctx.device = ibdev;
-	ctx->ibv_ctx.ops = qelr_ctx_ops;
+	ctx->ibv_ctx.context.ops = qelr_ctx_ops;
 	ctx->db_pa = resp.db_pa;
 	ctx->db_size = resp.db_size;
 	ctx->max_send_wr = resp.max_send_wr;
@@ -205,6 +203,7 @@  static struct ibv_context *qelr_alloc_context(struct ibv_device *ibdev,
 cmd_err:
 	qelr_err("%s: Failed to allocate context for device.\n", __func__);
 	qelr_close_debug_file(ctx);
+	verbs_uninit_context(&ctx->ibv_ctx);
 	free(ctx);
 	return NULL;
 }
@@ -217,6 +216,7 @@  static void qelr_free_context(struct ibv_context *ibctx)
 		munmap(ctx->db_addr, ctx->db_size);
 
 	qelr_close_debug_file(ctx);
+	verbs_uninit_context(&ctx->ibv_ctx);
 	free(ctx);
 }
 
diff --git a/providers/qedr/qelr_verbs.c b/providers/qedr/qelr_verbs.c
index 7db0fb3216dde9..5d7aeb37453c44 100644
--- a/providers/qedr/qelr_verbs.c
+++ b/providers/qedr/qelr_verbs.c
@@ -887,7 +887,7 @@  static inline void qelr_init_dpm_info(struct qelr_devctx *cxt,
 	dpm->is_edpm = 0;
 
 	/* Currently dpm is not supported for iWARP */
-	if (IS_IWARP(cxt->ibv_ctx.device))
+	if (IS_IWARP(cxt->ibv_ctx.context.device))
 		return;
 
 	if (qelr_chain_is_full(&qp->sq.chain) &&
diff --git a/providers/rxe/rxe.c b/providers/rxe/rxe.c
index 683ffaa2a8af9c..5cfdf1aac08a86 100644
--- a/providers/rxe/rxe.c
+++ b/providers/rxe/rxe.c
@@ -858,29 +858,27 @@  static struct ibv_context_ops rxe_ctx_ops = {
 	.detach_mcast = ibv_cmd_detach_mcast
 };
 
-static struct ibv_context *rxe_alloc_context(struct ibv_device *ibdev,
-					     int cmd_fd)
+static struct verbs_context *rxe_alloc_context(struct ibv_device *ibdev,
+					       int cmd_fd)
 {
 	struct rxe_context *context;
 	struct ibv_get_context cmd;
 	struct ibv_get_context_resp resp;
 
-	context = malloc(sizeof *context);
+	context = verbs_init_and_alloc_context(ibdev, cmd_fd, context, ibv_ctx);
 	if (!context)
 		return NULL;
 
-	memset(context, 0, sizeof *context);
-	context->ibv_ctx.cmd_fd = cmd_fd;
-
 	if (ibv_cmd_get_context(&context->ibv_ctx, &cmd,
 				sizeof cmd, &resp, sizeof resp))
 		goto out;
 
-	context->ibv_ctx.ops = rxe_ctx_ops;
+	context->ibv_ctx.context.ops = rxe_ctx_ops;
 
 	return &context->ibv_ctx;
 
 out:
+	verbs_uninit_context(&context->ibv_ctx);
 	free(context);
 	return NULL;
 }
@@ -889,6 +887,7 @@  static void rxe_free_context(struct ibv_context *ibctx)
 {
 	struct rxe_context *context = to_rctx(ibctx);
 
+	verbs_uninit_context(&context->ibv_ctx);
 	free(context);
 }
 
diff --git a/providers/rxe/rxe.h b/providers/rxe/rxe.h
index 1f331662b2ba2d..3fc0436127e432 100644
--- a/providers/rxe/rxe.h
+++ b/providers/rxe/rxe.h
@@ -54,7 +54,7 @@  struct rxe_device {
 };
 
 struct rxe_context {
-	struct ibv_context	ibv_ctx;
+	struct verbs_context	ibv_ctx;
 };
 
 struct rxe_cq {
@@ -98,7 +98,7 @@  struct rxe_srq {
 
 static inline struct rxe_context *to_rctx(struct ibv_context *ibctx)
 {
-	return to_rxxx(ctx, context);
+	return container_of(ibctx, struct rxe_context, ibv_ctx.context);
 }
 
 static inline struct rxe_device *to_rdev(struct ibv_device *ibdev)
diff --git a/providers/vmw_pvrdma/pvrdma.h b/providers/vmw_pvrdma/pvrdma.h
index 3bcec1cb71d14d..58165cf434b721 100644
--- a/providers/vmw_pvrdma/pvrdma.h
+++ b/providers/vmw_pvrdma/pvrdma.h
@@ -105,7 +105,7 @@  struct pvrdma_device {
 };
 
 struct pvrdma_context {
-	struct ibv_context		ibv_ctx;
+	struct verbs_context		ibv_ctx;
 	void				*uar;
 	pthread_spinlock_t		uar_lock;
 	int				max_qp_wr;
@@ -201,7 +201,7 @@  static inline struct pvrdma_device *to_vdev(struct ibv_device *ibdev)
 
 static inline struct pvrdma_context *to_vctx(struct ibv_context *ibctx)
 {
-	return container_of(ibctx, struct pvrdma_context, ibv_ctx);
+	return container_of(ibctx, struct pvrdma_context, ibv_ctx.context);
 }
 
 static inline struct pvrdma_pd *to_vpd(struct ibv_pd *ibpd)
diff --git a/providers/vmw_pvrdma/pvrdma_main.c b/providers/vmw_pvrdma/pvrdma_main.c
index 17736cd0079036..08b1d4e6d34f07 100644
--- a/providers/vmw_pvrdma/pvrdma_main.c
+++ b/providers/vmw_pvrdma/pvrdma_main.c
@@ -111,7 +111,7 @@  static int pvrdma_init_context_shared(struct pvrdma_context *context,
 	struct ibv_get_context cmd;
 	struct user_pvrdma_alloc_ucontext_resp resp;
 
-	context->ibv_ctx.cmd_fd = cmd_fd;
+	context->ibv_ctx.context.cmd_fd = cmd_fd;
 	if (ibv_cmd_get_context(&context->ibv_ctx, &cmd, sizeof(cmd),
 				&resp.ibv_resp, sizeof(resp)))
 		return errno;
@@ -129,7 +129,7 @@  static int pvrdma_init_context_shared(struct pvrdma_context *context,
 	}
 
 	pthread_spin_init(&context->uar_lock, PTHREAD_PROCESS_PRIVATE);
-	context->ibv_ctx.ops = pvrdma_ctx_ops;
+	context->ibv_ctx.context.ops = pvrdma_ctx_ops;
 
 	return 0;
 }
@@ -141,18 +141,17 @@  static void pvrdma_free_context_shared(struct pvrdma_context *context,
 	free(context->qp_tbl);
 }
 
-static struct ibv_context *pvrdma_alloc_context(struct ibv_device *ibdev,
-						int cmd_fd)
+static struct verbs_context *pvrdma_alloc_context(struct ibv_device *ibdev,
+						  int cmd_fd)
 {
 	struct pvrdma_context *context;
 
-	context = malloc(sizeof(*context));
+	context = verbs_init_and_alloc_context(ibdev, cmd_fd, context, ibv_ctx);
 	if (!context)
 		return NULL;
 
-	memset(context, 0, sizeof(*context));
-
 	if (pvrdma_init_context_shared(context, ibdev, cmd_fd)) {
+		verbs_uninit_context(&context->ibv_ctx);
 		free(context);
 		return NULL;
 	}
@@ -165,6 +164,7 @@  static void pvrdma_free_context(struct ibv_context *ibctx)
 	struct pvrdma_context *context = to_vctx(ibctx);
 
 	pvrdma_free_context_shared(context, to_vdev(ibctx->device));
+	verbs_uninit_context(&context->ibv_ctx);
 	free(context);
 }