aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland Dreier <rolandd@cisco.com>2005-08-31 18:39:26 +0000
committerRoland Dreier <rolandd@cisco.com>2006-11-09 11:35:57 -0800
commitfa9d62ef07ed0ac6085e0a61038566d3708342f2 (patch)
treeba0dfac74f9ab55fef922d432e9975fea24408b6
parentba45740a3c6090956d1aa1f1d10cbbcce8f62a97 (diff)
downloadlibibverbs-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--ChangeLog9
-rw-r--r--configure.in4
-rw-r--r--debian/changelog2
-rw-r--r--examples/asyncwatch.c2
-rw-r--r--include/infiniband/kern-abi.h42
-rw-r--r--include/infiniband/verbs.h27
-rw-r--r--src/cmd.c78
-rw-r--r--src/device.c82
-rw-r--r--src/ibverbs.h2
-rw-r--r--src/init.c10
-rw-r--r--src/libibverbs.map1
-rw-r--r--src/verbs.c31
12 files changed, 260 insertions, 30 deletions
diff --git a/ChangeLog b/ChangeLog
index 8b4848b..9b6283f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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,
diff --git a/src/cmd.c b/src/cmd.c
index 73c0abf..d7b34cd 100644
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -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);
diff --git a/src/init.c b/src/init.c
index 4a0ee2f..f4d4fc0 100644
--- a/src/init.c
+++ b/src/init.c
@@ -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;