diff options
author | Roland Dreier <rolandd@cisco.com> | 2005-08-31 18:39:26 +0000 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2006-11-09 11:35:57 -0800 |
commit | fa9d62ef07ed0ac6085e0a61038566d3708342f2 (patch) | |
tree | ba0dfac74f9ab55fef922d432e9975fea24408b6 | |
parent | ba45740a3c6090956d1aa1f1d10cbbcce8f62a97 (diff) | |
download | libibverbs-fa9d62ef07ed0ac6085e0a61038566d3708342f2.tar.gz |
Update for new kernel ABI (stale event handling)
Update to handle new kernel ABI for avoiding stale asynchronous
events. When a CQ, QP or SRQ is destroyed, the kernel reports the
number of events it has given to userspace, and we wait until we've
handled the same number of events.
This does introduce a library API change: consumers are now required
to call ibv_put_async_event() to release every asynchronous event that
they retrieve via ibv_get_async_event().
Signed-off-by: Roland Dreier <rolandd@cisco.com>
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | configure.in | 4 | ||||
-rw-r--r-- | debian/changelog | 2 | ||||
-rw-r--r-- | examples/asyncwatch.c | 2 | ||||
-rw-r--r-- | include/infiniband/kern-abi.h | 42 | ||||
-rw-r--r-- | include/infiniband/verbs.h | 27 | ||||
-rw-r--r-- | src/cmd.c | 78 | ||||
-rw-r--r-- | src/device.c | 82 | ||||
-rw-r--r-- | src/ibverbs.h | 2 | ||||
-rw-r--r-- | src/init.c | 10 | ||||
-rw-r--r-- | src/libibverbs.map | 1 | ||||
-rw-r--r-- | src/verbs.c | 31 |
12 files changed, 260 insertions, 30 deletions
@@ -1,3 +1,12 @@ +2005-08-31 Roland Dreier <roland@cisco.com> + + * include/infiniband/kern-abi.h, include/infiniband/verbs.h, + src/cmd.c, src/device.c, src/ibverbs.h, src/init.c, src/verbs.c, + examples/asyncwatch.h: Update to handle new kernel ABI for + avoiding stale asynchronous events. When a CQ, QP or SRQ is + destroyed, the kernel reports the number of events it has given to + userspace, and we wait until we've handled the same number of events. + 2005-08-30 Roland Dreier <roland@cisco.com> * man/ibv_asyncwatch.1, man/ibv_devices.1, man/ibv_devinfo.1, diff --git a/configure.in b/configure.in index c3fa3f1..8cdf99c 100644 --- a/configure.in +++ b/configure.in @@ -1,11 +1,11 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.57) -AC_INIT(libibverbs, 1.0-rc1, openib-general@openib.org) +AC_INIT(libibverbs, 1.0-rc2, openib-general@openib.org) AC_CONFIG_SRCDIR([src/ibverbs.h]) AC_CONFIG_AUX_DIR(config) AM_CONFIG_HEADER(config.h) -AM_INIT_AUTOMAKE(libibverbs, 1.0-rc1) +AM_INIT_AUTOMAKE(libibverbs, 1.0-rc2) AM_PROG_LIBTOOL diff --git a/debian/changelog b/debian/changelog index a678e02..5676be2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -libibverbs (1.0-rc1-1) unstable; urgency=low +libibverbs (1.0-rc2-1) unstable; urgency=low * Initial Release. (Closes: #325752) diff --git a/examples/asyncwatch.c b/examples/asyncwatch.c index d06d04f..42a2219 100644 --- a/examples/asyncwatch.c +++ b/examples/asyncwatch.c @@ -85,6 +85,8 @@ int main(int argc, char *argv[]) printf(" event_type %d, port %d\n", event.event_type, event.element.port_num); + + ibv_put_async_event(&event); } return 0; diff --git a/include/infiniband/kern-abi.h b/include/infiniband/kern-abi.h index 110f851..980aa05 100644 --- a/include/infiniband/kern-abi.h +++ b/include/infiniband/kern-abi.h @@ -44,10 +44,10 @@ */ /* - * Increment this value if any changes that break userspace ABI - * compatibility are made. + * The minimum and maximum kernel ABI that we can handle. */ -#define IB_USER_VERBS_ABI_VERSION 1 +#define IB_USER_VERBS_MIN_ABI_VERSION 1 +#define IB_USER_VERBS_MAX_ABI_VERSION 2 enum { IB_USER_VERBS_CMD_QUERY_PARAMS, @@ -319,13 +319,25 @@ struct ibv_create_cq_resp { __u32 cqe; }; +struct ibv_destroy_cq_v1 { + __u32 command; + __u16 in_words; + __u16 out_words; + __u32 cq_handle; +}; + struct ibv_destroy_cq { __u32 command; __u16 in_words; __u16 out_words; + __u64 response; __u32 cq_handle; }; +struct ibv_destroy_cq_resp { + __u32 events_reported; +}; + struct ibv_create_qp { __u32 command; __u16 in_words; @@ -401,13 +413,25 @@ struct ibv_modify_qp { __u64 driver_data[0]; }; +struct ibv_destroy_qp_v1 { + __u32 command; + __u16 in_words; + __u16 out_words; + __u32 qp_handle; +}; + struct ibv_destroy_qp { __u32 command; __u16 in_words; __u16 out_words; + __u64 response; __u32 qp_handle; }; +struct ibv_destroy_qp_resp { + __u32 events_reported; +}; + struct ibv_attach_mcast { __u32 command; __u16 in_words; @@ -460,11 +484,23 @@ struct ibv_modify_srq { __u64 driver_data[0]; }; +struct ibv_destroy_srq_v1 { + __u32 command; + __u16 in_words; + __u16 out_words; + __u32 srq_handle; +}; + struct ibv_destroy_srq { __u32 command; __u16 in_words; __u16 out_words; + __u64 response; __u32 srq_handle; }; +struct ibv_destroy_srq_resp { + __u32 events_reported; +}; + #endif /* KERN_ABI_H */ diff --git a/include/infiniband/verbs.h b/include/infiniband/verbs.h index 0a6ccb7..66845be 100644 --- a/include/infiniband/verbs.h +++ b/include/infiniband/verbs.h @@ -38,6 +38,7 @@ #define INFINIBAND_VERBS_H #include <stdint.h> +#include <pthread.h> #include <sysfs/libsysfs.h> @@ -471,6 +472,10 @@ struct ibv_srq { void *srq_context; struct ibv_pd *pd; uint32_t handle; + + pthread_mutex_t mutex; + pthread_cond_t cond; + uint32_t events_completed; }; struct ibv_qp { @@ -483,6 +488,10 @@ struct ibv_qp { uint32_t handle; uint32_t qp_num; enum ibv_qp_state state; + + pthread_mutex_t mutex; + pthread_cond_t cond; + uint32_t events_completed; }; struct ibv_cq { @@ -490,6 +499,10 @@ struct ibv_cq { void *cq_context; uint32_t handle; int cqe; + + pthread_mutex_t mutex; + pthread_cond_t cond; + uint32_t events_completed; }; struct ibv_ah { @@ -593,11 +606,25 @@ extern int ibv_close_device(struct ibv_context *context); /** * ibv_get_async_event - Get next async event + * @event: Pointer to use to return async event + * + * The event returned must eventually be released via ibv_put_async_event(). */ extern int ibv_get_async_event(struct ibv_context *context, struct ibv_async_event *event); /** + * ibv_put_async_event - Free an async event + * @event: Event to be released. + * + * All events which are returned by ib_get_async_event() must be + * released. There should be a one-to-one correspondence between + * successful gets and puts. + */ +extern void ibv_put_async_event(struct ibv_async_event *event); + + +/** * ibv_query_device - Get device properties */ extern int ibv_query_device(struct ibv_context *context, @@ -275,9 +275,9 @@ int ibv_cmd_create_cq(struct ibv_context *context, int cqe, return 0; } -int ibv_cmd_destroy_cq(struct ibv_cq *cq) +static int ibv_cmd_destroy_cq_v1(struct ibv_cq *cq) { - struct ibv_destroy_cq cmd; + struct ibv_destroy_cq_v1 cmd; IBV_INIT_CMD(&cmd, sizeof cmd, DESTROY_CQ); cmd.cq_handle = cq->handle; @@ -288,6 +288,28 @@ int ibv_cmd_destroy_cq(struct ibv_cq *cq) return 0; } +int ibv_cmd_destroy_cq(struct ibv_cq *cq) +{ + struct ibv_destroy_cq cmd; + struct ibv_destroy_cq_resp resp; + + if (abi_ver == 1) + return ibv_cmd_destroy_cq_v1(cq); + + IBV_INIT_CMD_RESP(&cmd, sizeof cmd, DESTROY_CQ, &resp, sizeof resp); + cmd.cq_handle = cq->handle; + + if (write(cq->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + pthread_mutex_lock(&cq->mutex); + while (cq->events_completed != resp.events_reported) + pthread_cond_wait(&cq->cond, &cq->mutex); + pthread_mutex_unlock(&cq->mutex); + + return 0; +} + int ibv_cmd_create_srq(struct ibv_pd *pd, struct ibv_srq *srq, struct ibv_srq_init_attr *attr, struct ibv_create_srq *cmd, size_t cmd_size, @@ -308,9 +330,9 @@ int ibv_cmd_create_srq(struct ibv_pd *pd, return 0; } -int ibv_cmd_destroy_srq(struct ibv_srq *srq) +static int ibv_cmd_destroy_srq_v1(struct ibv_srq *srq) { - struct ibv_destroy_srq cmd; + struct ibv_destroy_srq_v1 cmd; IBV_INIT_CMD(&cmd, sizeof cmd, DESTROY_SRQ); cmd.srq_handle = srq->handle; @@ -321,6 +343,28 @@ int ibv_cmd_destroy_srq(struct ibv_srq *srq) return 0; } +int ibv_cmd_destroy_srq(struct ibv_srq *srq) +{ + struct ibv_destroy_srq cmd; + struct ibv_destroy_srq_resp resp; + + if (abi_ver == 1) + return ibv_cmd_destroy_srq_v1(srq); + + IBV_INIT_CMD_RESP(&cmd, sizeof cmd, DESTROY_SRQ, &resp, sizeof resp); + cmd.srq_handle = srq->handle; + + if (write(srq->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + pthread_mutex_lock(&srq->mutex); + while (srq->events_completed != resp.events_reported) + pthread_cond_wait(&srq->cond, &srq->mutex); + pthread_mutex_unlock(&srq->mutex); + + return 0; +} + int ibv_cmd_create_qp(struct ibv_pd *pd, struct ibv_qp *qp, struct ibv_qp_init_attr *attr, struct ibv_create_qp *cmd, size_t cmd_size) @@ -411,9 +455,9 @@ int ibv_cmd_modify_qp(struct ibv_qp *qp, struct ibv_qp_attr *attr, return 0; } -int ibv_cmd_destroy_qp(struct ibv_qp *qp) +static int ibv_cmd_destroy_qp_v1(struct ibv_qp *qp) { - struct ibv_destroy_qp cmd; + struct ibv_destroy_qp_v1 cmd; IBV_INIT_CMD(&cmd, sizeof cmd, DESTROY_QP); cmd.qp_handle = qp->handle; @@ -424,6 +468,28 @@ int ibv_cmd_destroy_qp(struct ibv_qp *qp) return 0; } +int ibv_cmd_destroy_qp(struct ibv_qp *qp) +{ + struct ibv_destroy_qp cmd; + struct ibv_destroy_qp_resp resp; + + if (abi_ver == 1) + return ibv_cmd_destroy_qp_v1(qp); + + IBV_INIT_CMD_RESP(&cmd, sizeof cmd, DESTROY_QP, &resp, sizeof resp); + cmd.qp_handle = qp->handle; + + if (write(qp->context->cmd_fd, &cmd, sizeof cmd) != sizeof cmd) + return errno; + + pthread_mutex_lock(&qp->mutex); + while (qp->events_completed != resp.events_reported) + pthread_cond_wait(&qp->cond, &qp->mutex); + pthread_mutex_unlock(&qp->mutex); + + return 0; +} + int ibv_cmd_attach_mcast(struct ibv_qp *qp, union ibv_gid *gid, uint16_t lid) { struct ibv_attach_mcast cmd; diff --git a/src/device.c b/src/device.c index 4df506d..650d7dc 100644 --- a/src/device.c +++ b/src/device.c @@ -140,9 +140,85 @@ int ibv_get_async_event(struct ibv_context *context, if (read(context->async_fd, &ev, sizeof ev) != sizeof ev) return -1; - /* XXX convert CQ/QP handles back to pointers */ - event->element.port_num = ev.element; - event->event_type = ev.event_type; + event->event_type = ev.event_type; + + switch (event->event_type) { + case IBV_EVENT_CQ_ERR: + event->element.cq = (void *) (uintptr_t) ev.element; + break; + + case IBV_EVENT_QP_FATAL: + case IBV_EVENT_QP_REQ_ERR: + case IBV_EVENT_QP_ACCESS_ERR: + case IBV_EVENT_COMM_EST: + case IBV_EVENT_SQ_DRAINED: + case IBV_EVENT_PATH_MIG: + case IBV_EVENT_PATH_MIG_ERR: + case IBV_EVENT_QP_LAST_WQE_REACHED: + event->element.qp = (void *) (uintptr_t) ev.element; + break; + + case IBV_EVENT_SRQ_ERR: + case IBV_EVENT_SRQ_LIMIT_REACHED: + event->element.srq = (void *) (uintptr_t) ev.element; + break; + + default: + event->element.port_num = ev.element; + break; + } return 0; } + +void ibv_put_async_event(struct ibv_async_event *event) +{ + switch (event->event_type) { + case IBV_EVENT_CQ_ERR: + { + struct ibv_cq *cq = event->element.cq; + + pthread_mutex_lock(&cq->mutex); + ++cq->events_completed; + pthread_cond_signal(&cq->cond); + pthread_mutex_unlock(&cq->mutex); + + return; + } + + case IBV_EVENT_QP_FATAL: + case IBV_EVENT_QP_REQ_ERR: + case IBV_EVENT_QP_ACCESS_ERR: + case IBV_EVENT_COMM_EST: + case IBV_EVENT_SQ_DRAINED: + case IBV_EVENT_PATH_MIG: + case IBV_EVENT_PATH_MIG_ERR: + case IBV_EVENT_QP_LAST_WQE_REACHED: + { + struct ibv_qp *qp = event->element.qp; + + pthread_mutex_lock(&qp->mutex); + ++qp->events_completed; + pthread_cond_signal(&qp->cond); + pthread_mutex_unlock(&qp->mutex); + + return; + } + + case IBV_EVENT_SRQ_ERR: + case IBV_EVENT_SRQ_LIMIT_REACHED: + { + struct ibv_srq *srq = event->element.srq; + + pthread_mutex_lock(&srq->mutex); + ++srq->events_completed; + pthread_cond_signal(&srq->cond); + pthread_mutex_unlock(&srq->mutex); + + return; + } + + default: + return; + } +} diff --git a/src/ibverbs.h b/src/ibverbs.h index 58565c8..0953686 100644 --- a/src/ibverbs.h +++ b/src/ibverbs.h @@ -50,6 +50,8 @@ struct ibv_driver { ibv_driver_init_func init_func; }; +extern HIDDEN int abi_ver; + extern struct dlist *ibverbs_init(void); extern int ibv_init_mem_map(void); @@ -50,6 +50,8 @@ # define OPENIB_DRIVER_PATH_ENV "OPENIB_DRIVER_PATH" #endif +HIDDEN int abi_ver; + static char default_path[] = DRIVER_PATH; static const char *user_path; @@ -159,7 +161,6 @@ static int check_abi_version(void) { char path[256]; char val[16]; - int ver; if (sysfs_get_mnt_path(path, sizeof path)) { fprintf(stderr, PFX "Fatal: couldn't find sysfs mount.\n"); @@ -173,12 +174,13 @@ static int check_abi_version(void) return -1; } - ver = strtol(val, NULL, 10); + abi_ver = strtol(val, NULL, 10); - if (ver != IB_USER_VERBS_ABI_VERSION) { + if (abi_ver < IB_USER_VERBS_MIN_ABI_VERSION || + abi_ver > IB_USER_VERBS_MAX_ABI_VERSION) { fprintf(stderr, PFX "Fatal: kernel ABI version %d " "doesn't match library version %d.\n", - ver, IB_USER_VERBS_ABI_VERSION); + abi_ver, IB_USER_VERBS_MAX_ABI_VERSION); return -1; } diff --git a/src/libibverbs.map b/src/libibverbs.map index f4a3cc3..6a445b5 100644 --- a/src/libibverbs.map +++ b/src/libibverbs.map @@ -6,6 +6,7 @@ IBVERBS_1.0 { ibv_open_device; ibv_close_device; ibv_get_async_event; + ibv_put_async_event; ibv_query_device; ibv_query_port; ibv_query_gid; diff --git a/src/verbs.c b/src/verbs.c index 5f239a8..0d6925e 100644 --- a/src/verbs.c +++ b/src/verbs.c @@ -107,8 +107,11 @@ struct ibv_cq *ibv_create_cq(struct ibv_context *context, int cqe, struct ibv_cq *cq = context->ops.create_cq(context, cqe); if (cq) { - cq->context = context; - cq->cq_context = cq_context; + cq->context = context; + cq->cq_context = cq_context; + cq->events_completed = 0; + pthread_mutex_init(&cq->mutex, NULL); + pthread_cond_init(&cq->cond, NULL); } return cq; @@ -146,9 +149,12 @@ struct ibv_srq *ibv_create_srq(struct ibv_pd *pd, struct ibv_srq *srq = pd->context->ops.create_srq(pd, srq_init_attr); if (srq) { - srq->context = pd->context; - srq->srq_context = srq_init_attr->srq_context; - srq->pd = pd; + srq->context = pd->context; + srq->srq_context = srq_init_attr->srq_context; + srq->pd = pd; + srq->events_completed = 0; + pthread_mutex_init(&srq->mutex, NULL); + pthread_cond_init(&srq->cond, NULL); } return srq; @@ -172,12 +178,15 @@ struct ibv_qp *ibv_create_qp(struct ibv_pd *pd, struct ibv_qp *qp = pd->context->ops.create_qp(pd, qp_init_attr); if (qp) { - qp->context = pd->context; - qp->qp_context = qp_init_attr->qp_context; - qp->pd = pd; - qp->send_cq = qp_init_attr->send_cq; - qp->recv_cq = qp_init_attr->recv_cq; - qp->srq = qp_init_attr->srq; + qp->context = pd->context; + qp->qp_context = qp_init_attr->qp_context; + qp->pd = pd; + qp->send_cq = qp_init_attr->send_cq; + qp->recv_cq = qp_init_attr->recv_cq; + qp->srq = qp_init_attr->srq; + qp->events_completed = 0; + pthread_mutex_init(&qp->mutex, NULL); + pthread_cond_init(&qp->cond, NULL); } return qp; |