diff options
author | Roland Dreier <roland@eddore.topspincom.com> | 2005-09-09 15:55:08 -0700 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2005-09-09 15:55:08 -0700 |
commit | 63aaf647529e8a56bdf31fd8f2979d4371c6a332 (patch) | |
tree | dd1ed29d591da4ef6ec0c4260d59b1910010c314 /drivers/infiniband/core/uverbs_main.c | |
parent | 2e9f7cb7869059e55cd91f5e23c6380f3763db56 (diff) |
Make sure that userspace does not retrieve stale asynchronous or
completion events after destroying a CQ, QP or SRQ. We do this by
sweeping the event lists before returning from a destroy calls, and
then return the number of events already reported before the destroy
call. This allows userspace wait until it has processed all events
for an object returned from the kernel before it frees its context for
the object.
The ABI of the destroy CQ, destroy QP and destroy SRQ commands has to
change to return the event count, so bump the ABI version from 1 to 2.
The userspace libibverbs library has already been updated to handle
both the old and new ABI versions.
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/core/uverbs_main.c')
-rw-r--r-- | drivers/infiniband/core/uverbs_main.c | 98 |
1 files changed, 62 insertions, 36 deletions
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 09caf5b1ef3..ce5bdb7af30 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -120,7 +120,7 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context) idr_remove(&ib_uverbs_qp_idr, uobj->id); ib_destroy_qp(qp); list_del(&uobj->list); - kfree(uobj); + kfree(container_of(uobj, struct ib_uevent_object, uobject)); } list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) { @@ -128,7 +128,7 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context) idr_remove(&ib_uverbs_cq_idr, uobj->id); ib_destroy_cq(cq); list_del(&uobj->list); - kfree(uobj); + kfree(container_of(uobj, struct ib_ucq_object, uobject)); } list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) { @@ -136,7 +136,7 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context) idr_remove(&ib_uverbs_srq_idr, uobj->id); ib_destroy_srq(srq); list_del(&uobj->list); - kfree(uobj); + kfree(container_of(uobj, struct ib_uevent_object, uobject)); } /* XXX Free MWs */ @@ -182,7 +182,7 @@ static ssize_t ib_uverbs_event_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { struct ib_uverbs_event_file *file = filp->private_data; - void *event; + struct ib_uverbs_event *event; int eventsz; int ret = 0; @@ -207,21 +207,23 @@ static ssize_t ib_uverbs_event_read(struct file *filp, char __user *buf, return -ENODEV; } - if (file->is_async) { - event = list_entry(file->event_list.next, - struct ib_uverbs_async_event, list); + event = list_entry(file->event_list.next, struct ib_uverbs_event, list); + + if (file->is_async) eventsz = sizeof (struct ib_uverbs_async_event_desc); - } else { - event = list_entry(file->event_list.next, - struct ib_uverbs_comp_event, list); + else eventsz = sizeof (struct ib_uverbs_comp_event_desc); - } if (eventsz > count) { ret = -EINVAL; event = NULL; - } else + } else { list_del(file->event_list.next); + if (event->counter) { + ++(*event->counter); + list_del(&event->obj_list); + } + } spin_unlock_irq(&file->lock); @@ -257,16 +259,13 @@ static unsigned int ib_uverbs_event_poll(struct file *filp, static void ib_uverbs_event_release(struct ib_uverbs_event_file *file) { - struct list_head *entry, *tmp; + struct ib_uverbs_event *entry, *tmp; spin_lock_irq(&file->lock); if (file->fd != -1) { file->fd = -1; - list_for_each_safe(entry, tmp, &file->event_list) - if (file->is_async) - kfree(list_entry(entry, struct ib_uverbs_async_event, list)); - else - kfree(list_entry(entry, struct ib_uverbs_comp_event, list)); + list_for_each_entry_safe(entry, tmp, &file->event_list, list) + kfree(entry); } spin_unlock_irq(&file->lock); } @@ -304,18 +303,23 @@ static struct file_operations uverbs_event_fops = { void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context) { - struct ib_uverbs_file *file = cq_context; - struct ib_uverbs_comp_event *entry; - unsigned long flags; + struct ib_uverbs_file *file = cq_context; + struct ib_ucq_object *uobj; + struct ib_uverbs_event *entry; + unsigned long flags; entry = kmalloc(sizeof *entry, GFP_ATOMIC); if (!entry) return; - entry->desc.cq_handle = cq->uobject->user_handle; + uobj = container_of(cq->uobject, struct ib_ucq_object, uobject); + + entry->desc.comp.cq_handle = cq->uobject->user_handle; + entry->counter = &uobj->comp_events_reported; spin_lock_irqsave(&file->comp_file[0].lock, flags); list_add_tail(&entry->list, &file->comp_file[0].event_list); + list_add_tail(&entry->obj_list, &uobj->comp_list); spin_unlock_irqrestore(&file->comp_file[0].lock, flags); wake_up_interruptible(&file->comp_file[0].poll_wait); @@ -323,20 +327,25 @@ void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context) } static void ib_uverbs_async_handler(struct ib_uverbs_file *file, - __u64 element, __u64 event) + __u64 element, __u64 event, + struct list_head *obj_list, + u32 *counter) { - struct ib_uverbs_async_event *entry; + struct ib_uverbs_event *entry; unsigned long flags; entry = kmalloc(sizeof *entry, GFP_ATOMIC); if (!entry) return; - entry->desc.element = element; - entry->desc.event_type = event; + entry->desc.async.element = element; + entry->desc.async.event_type = event; + entry->counter = counter; spin_lock_irqsave(&file->async_file.lock, flags); list_add_tail(&entry->list, &file->async_file.event_list); + if (obj_list) + list_add_tail(&entry->obj_list, obj_list); spin_unlock_irqrestore(&file->async_file.lock, flags); wake_up_interruptible(&file->async_file.poll_wait); @@ -345,23 +354,39 @@ static void ib_uverbs_async_handler(struct ib_uverbs_file *file, void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr) { - ib_uverbs_async_handler(context_ptr, - event->element.cq->uobject->user_handle, - event->event); + struct ib_ucq_object *uobj; + + uobj = container_of(event->element.cq->uobject, + struct ib_ucq_object, uobject); + + ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle, + event->event, &uobj->async_list, + &uobj->async_events_reported); + } void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr) { - ib_uverbs_async_handler(context_ptr, - event->element.qp->uobject->user_handle, - event->event); + struct ib_uevent_object *uobj; + + uobj = container_of(event->element.qp->uobject, + struct ib_uevent_object, uobject); + + ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle, + event->event, &uobj->event_list, + &uobj->events_reported); } void ib_uverbs_srq_event_handler(struct ib_event *event, void *context_ptr) { - ib_uverbs_async_handler(context_ptr, - event->element.srq->uobject->user_handle, - event->event); + struct ib_uevent_object *uobj; + + uobj = container_of(event->element.srq->uobject, + struct ib_uevent_object, uobject); + + ib_uverbs_async_handler(context_ptr, uobj->uobject.user_handle, + event->event, &uobj->event_list, + &uobj->events_reported); } static void ib_uverbs_event_handler(struct ib_event_handler *handler, @@ -370,7 +395,8 @@ static void ib_uverbs_event_handler(struct ib_event_handler *handler, struct ib_uverbs_file *file = container_of(handler, struct ib_uverbs_file, event_handler); - ib_uverbs_async_handler(file, event->element.port_num, event->event); + ib_uverbs_async_handler(file, event->element.port_num, event->event, + NULL, NULL); } static int ib_uverbs_event_init(struct ib_uverbs_event_file *file, |