This makes async events aligned with completion events as both are full uobjects of FD type and use the same uobject lifecycle. A bunch of duplicate code is consolidated and the general flow between the two FDs is now very similar.
Unified · Split
| @@ -35,6 +35,7 @@ ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_marshall.o \ · 34 unmodified lines | |||
| 35 | uverbs_std_types_cq.o \ | 35 | uverbs_std_types_cq.o \ |
| 36 | uverbs_std_types_flow_action.o uverbs_std_types_dm.o \ | 36 | uverbs_std_types_flow_action.o uverbs_std_types_dm.o \ |
| 37 | uverbs_std_types_mr.o uverbs_std_types_counters.o \ | 37 | uverbs_std_types_mr.o uverbs_std_types_counters.o \ |
| 38 | uverbs_uapi.o uverbs_std_types_device.o | 38 | uverbs_uapi.o uverbs_std_types_device.o \ |
| 39 | uverbs_std_types_async_fd.o | ||
| 39 | ib_uverbs-$(CONFIG_INFINIBAND_USER_MEM) += umem.o | 40 | ib_uverbs-$(CONFIG_INFINIBAND_USER_MEM) += umem.o |
| 40 | ib_uverbs-$(CONFIG_INFINIBAND_ON_DEMAND_PAGING) += umem_odp.o | 41 | ib_uverbs-$(CONFIG_INFINIBAND_ON_DEMAND_PAGING) += umem_odp.o |
| @@ -151,6 +151,7 @@ void uapi_compute_bundle_size(struct uverbs_api_ioctl_method *method_elm, · 150 unmodified lines | |||
| 151 | unsigned int num_attrs); | 151 | unsigned int num_attrs); |
| 152 | void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile); | 152 | void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile); |
| 153 | 153 | ||
| 154 | extern const struct uapi_definition uverbs_def_obj_async_fd[]; | ||
| 154 | extern const struct uapi_definition uverbs_def_obj_counters[]; | 155 | extern const struct uapi_definition uverbs_def_obj_counters[]; |
| 155 | extern const struct uapi_definition uverbs_def_obj_cq[]; | 156 | extern const struct uapi_definition uverbs_def_obj_cq[]; |
| 156 | extern const struct uapi_definition uverbs_def_obj_device[]; | 157 | extern const struct uapi_definition uverbs_def_obj_device[]; |
| @@ -111,7 +111,6 @@ struct ib_uverbs_device { · 110 unmodified lines | |||
| 111 | struct srcu_struct disassociate_srcu; | 111 | struct srcu_struct disassociate_srcu; |
| 112 | struct mutex lists_mutex; /* protect lists */ | 112 | struct mutex lists_mutex; /* protect lists */ |
| 113 | struct list_head uverbs_file_list; | 113 | struct list_head uverbs_file_list; |
| 114 | struct list_head uverbs_events_file_list; | ||
| 115 | struct uverbs_api *uapi; | 114 | struct uverbs_api *uapi; |
| 116 | }; | 115 | }; |
| 117 | 116 | ||
| @@ -124,10 +123,9 @@ struct ib_uverbs_event_queue { · 6 unmodified lines | |||
| 124 | }; | 123 | }; |
| 125 | 124 | ||
| 126 | struct ib_uverbs_async_event_file { | 125 | struct ib_uverbs_async_event_file { |
| 126 | struct ib_uobject uobj; | ||
| 127 | struct ib_uverbs_event_queue ev_queue; | 127 | struct ib_uverbs_event_queue ev_queue; |
| 128 | struct ib_uverbs_file *uverbs_file; | 128 | struct ib_event_handler event_handler; |
| 129 | struct kref ref; | ||
| 130 | struct list_head list; | ||
| 131 | }; | 129 | }; |
| 132 | 130 | ||
| 133 | struct ib_uverbs_completion_event_file { | 131 | struct ib_uverbs_completion_event_file { |
| @@ -144,8 +142,7 @@ struct ib_uverbs_file { · 10 unmodified lines | |||
| 144 | * ucontext_lock held | 142 | * ucontext_lock held |
| 145 | */ | 143 | */ |
| 146 | struct ib_ucontext *ucontext; | 144 | struct ib_ucontext *ucontext; |
| 147 | struct ib_event_handler event_handler; | 145 | struct ib_uverbs_async_event_file *async_file; |
| 148 | struct ib_uverbs_async_event_file *async_file; | ||
| 149 | struct list_head list; | 146 | struct list_head list; |
| 150 | 147 | ||
| 151 | /* | 148 | /* |
| @@ -217,10 +214,10 @@ struct ib_ucq_object { · 65 unmodified lines | |||
| 217 | }; | 214 | }; |
| 218 | 215 | ||
| 219 | extern const struct file_operations uverbs_event_fops; | 216 | extern const struct file_operations uverbs_event_fops; |
| 217 | extern const struct file_operations uverbs_async_event_fops; | ||
| 220 | void ib_uverbs_init_event_queue(struct ib_uverbs_event_queue *ev_queue); | 218 | void ib_uverbs_init_event_queue(struct ib_uverbs_event_queue *ev_queue); |
| 221 | struct file *ib_uverbs_alloc_async_event_file(struct ib_uverbs_file *uverbs_file, | 219 | void ib_uverbs_init_async_event_file(struct ib_uverbs_async_event_file *ev_file); |
| 222 | struct ib_device *ib_dev); | 220 | void ib_uverbs_free_event_queue(struct ib_uverbs_event_queue *event_queue); |
| 223 | void ib_uverbs_free_async_event_file(struct ib_uverbs_file *uverbs_file); | ||
| 224 | void ib_uverbs_flow_resources_free(struct ib_uflow_resources *uflow_res); | 221 | void ib_uverbs_flow_resources_free(struct ib_uflow_resources *uflow_res); |
| 225 | 222 | ||
| 226 | void ib_uverbs_release_ucq(struct ib_uverbs_file *file, | 223 | void ib_uverbs_release_ucq(struct ib_uverbs_file *file, |
| @@ -209,9 +209,9 @@ static int ib_uverbs_get_context(struct uverbs_attr_bundle *attrs) · 208 unmodified lines | |||
| 209 | struct ib_uverbs_get_context cmd; | 209 | struct ib_uverbs_get_context cmd; |
| 210 | struct ib_uverbs_get_context_resp resp; | 210 | struct ib_uverbs_get_context_resp resp; |
| 211 | struct ib_ucontext *ucontext; | 211 | struct ib_ucontext *ucontext; |
| 212 | struct file *filp; | ||
| 213 | struct ib_rdmacg_object cg_obj; | 212 | struct ib_rdmacg_object cg_obj; |
| 214 | struct ib_device *ib_dev; | 213 | struct ib_device *ib_dev; |
| 214 | struct ib_uobject *uobj; | ||
| 215 | int ret; | 215 | int ret; |
| 216 | 216 | ||
| 217 | ret = uverbs_request(attrs, &cmd, sizeof(cmd)); | 217 | ret = uverbs_request(attrs, &cmd, sizeof(cmd)); |
| @@ -254,30 +254,28 @@ static int ib_uverbs_get_context(struct uverbs_attr_bundle *attrs) · 36 unmodified lines | |||
| 254 | 254 | ||
| 255 | xa_init_flags(&ucontext->mmap_xa, XA_FLAGS_ALLOC); | 255 | xa_init_flags(&ucontext->mmap_xa, XA_FLAGS_ALLOC); |
| 256 | 256 | ||
| 257 | ret = get_unused_fd_flags(O_CLOEXEC); | 257 | uobj = uobj_alloc(UVERBS_OBJECT_ASYNC_EVENT, attrs, &ib_dev); |
| 258 | if (ret < 0) | 258 | if (IS_ERR(uobj)) { |
| 259 | ret = PTR_ERR(uobj); | ||
| 259 | goto err_free; | 260 | goto err_free; |
| 260 | resp.async_fd = ret; | ||
| 261 | |||
| 262 | filp = ib_uverbs_alloc_async_event_file(file, ib_dev); | ||
| 263 | if (IS_ERR(filp)) { | ||
| 264 | ret = PTR_ERR(filp); | ||
| 265 | goto err_fd; | ||
| 266 | } | 261 | } |
| 267 | 262 | ||
| 263 | resp.async_fd = uobj->id; | ||
| 268 | resp.num_comp_vectors = file->device->num_comp_vectors; | 264 | resp.num_comp_vectors = file->device->num_comp_vectors; |
| 269 | 265 | ||
| 270 | ret = uverbs_response(attrs, &resp, sizeof(resp)); | 266 | ret = uverbs_response(attrs, &resp, sizeof(resp)); |
| 271 | if (ret) | 267 | if (ret) |
| 272 | goto err_file; | 268 | goto err_uobj; |
| 273 | 269 | ||
| 274 | ret = ib_dev->ops.alloc_ucontext(ucontext, &attrs->driver_udata); | 270 | ret = ib_dev->ops.alloc_ucontext(ucontext, &attrs->driver_udata); |
| 275 | if (ret) | 271 | if (ret) |
| 276 | goto err_file; | 272 | goto err_uobj; |
| 277 | 273 | ||
| 278 | rdma_restrack_uadd(&ucontext->res); | 274 | rdma_restrack_uadd(&ucontext->res); |
| 279 | 275 | ||
| 280 | fd_install(resp.async_fd, filp); | 276 | ib_uverbs_init_async_event_file( |
| 277 | container_of(uobj, struct ib_uverbs_async_event_file, uobj)); | ||
| 278 | rdma_alloc_commit_uobject(uobj, attrs); | ||
| 281 | 279 | ||
| 282 | /* | 280 | /* |
| 283 | * Make sure that ib_uverbs_get_ucontext() sees the pointer update | 281 | * Make sure that ib_uverbs_get_ucontext() sees the pointer update |
| @@ -289,12 +287,8 @@ static int ib_uverbs_get_context(struct uverbs_attr_bundle *attrs) · 5 unmodified lines | |||
| 289 | 287 | ||
| 290 | return 0; | 288 | return 0; |
| 291 | 289 | ||
| 292 | err_file: | 290 | err_uobj: |
| 293 | ib_uverbs_free_async_event_file(file); | 291 | rdma_alloc_abort_uobject(uobj, attrs); |
| 294 | fput(filp); | ||
| 295 | |||
| 296 | err_fd: | ||
| 297 | put_unused_fd(resp.async_fd); | ||
| 298 | 292 | ||
| 299 | err_free: | 293 | err_free: |
| 300 | kfree(ucontext); | 294 | kfree(ucontext); |
| @@ -125,14 +125,6 @@ static void ib_uverbs_release_dev(struct device *device) · 124 unmodified lines | |||
| 125 | kfree(dev); | 125 | kfree(dev); |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | static void ib_uverbs_release_async_event_file(struct kref *ref) | ||
| 129 | { | ||
| 130 | struct ib_uverbs_async_event_file *file = | ||
| 131 | container_of(ref, struct ib_uverbs_async_event_file, ref); | ||
| 132 | |||
| 133 | kfree(file); | ||
| 134 | } | ||
| 135 | |||
| 136 | void ib_uverbs_release_ucq(struct ib_uverbs_file *file, | 128 | void ib_uverbs_release_ucq(struct ib_uverbs_file *file, |
| 137 | struct ib_uverbs_completion_event_file *ev_file, | 129 | struct ib_uverbs_completion_event_file *ev_file, |
| 138 | struct ib_ucq_object *uobj) | 130 | struct ib_ucq_object *uobj) |
| @@ -203,8 +195,7 @@ void ib_uverbs_release_file(struct kref *ref) · 64 unmodified lines | |||
| 203 | ib_uverbs_comp_dev(file->device); | 195 | ib_uverbs_comp_dev(file->device); |
| 204 | 196 | ||
| 205 | if (file->async_file) | 197 | if (file->async_file) |
| 206 | kref_put(&file->async_file->ref, | 198 | uverbs_uobject_put(&file->async_file->uobj); |
| 207 | ib_uverbs_release_async_event_file); | ||
| 208 | put_device(&file->device->dev); | 199 | put_device(&file->device->dev); |
| 209 | 200 | ||
| 210 | if (file->disassociate_page) | 201 | if (file->disassociate_page) |
| @@ -339,35 +330,6 @@ static int ib_uverbs_comp_event_fasync(int fd, struct file *filp, int on) · 128 unmodified lines | |||
| 339 | return fasync_helper(fd, filp, on, &comp_ev_file->ev_queue.async_queue); | 330 | return fasync_helper(fd, filp, on, &comp_ev_file->ev_queue.async_queue); |
| 340 | } | 331 | } |
| 341 | 332 | ||
| 342 | static int ib_uverbs_async_event_close(struct inode *inode, struct file *filp) | ||
| 343 | { | ||
| 344 | struct ib_uverbs_async_event_file *file = filp->private_data; | ||
| 345 | struct ib_uverbs_file *uverbs_file = file->uverbs_file; | ||
| 346 | struct ib_uverbs_event *entry, *tmp; | ||
| 347 | int closed_already = 0; | ||
| 348 | |||
| 349 | mutex_lock(&uverbs_file->device->lists_mutex); | ||
| 350 | spin_lock_irq(&file->ev_queue.lock); | ||
| 351 | closed_already = file->ev_queue.is_closed; | ||
| 352 | file->ev_queue.is_closed = 1; | ||
| 353 | list_for_each_entry_safe(entry, tmp, &file->ev_queue.event_list, list) { | ||
| 354 | if (entry->counter) | ||
| 355 | list_del(&entry->obj_list); | ||
| 356 | kfree(entry); | ||
| 357 | } | ||
| 358 | spin_unlock_irq(&file->ev_queue.lock); | ||
| 359 | if (!closed_already) { | ||
| 360 | list_del(&file->list); | ||
| 361 | ib_unregister_event_handler(&uverbs_file->event_handler); | ||
| 362 | } | ||
| 363 | mutex_unlock(&uverbs_file->device->lists_mutex); | ||
| 364 | |||
| 365 | kref_put(&uverbs_file->ref, ib_uverbs_release_file); | ||
| 366 | kref_put(&file->ref, ib_uverbs_release_async_event_file); | ||
| 367 | |||
| 368 | return 0; | ||
| 369 | } | ||
| 370 | |||
| 371 | const struct file_operations uverbs_event_fops = { | 333 | const struct file_operations uverbs_event_fops = { |
| 372 | .owner = THIS_MODULE, | 334 | .owner = THIS_MODULE, |
| 373 | .read = ib_uverbs_comp_event_read, | 335 | .read = ib_uverbs_comp_event_read, |
| @@ -377,11 +339,11 @@ const struct file_operations uverbs_event_fops = { · 3 unmodified lines | |||
| 377 | .llseek = no_llseek, | 339 | .llseek = no_llseek, |
| 378 | }; | 340 | }; |
| 379 | 341 | ||
| 380 | static const struct file_operations uverbs_async_event_fops = { | 342 | const struct file_operations uverbs_async_event_fops = { |
| 381 | .owner = THIS_MODULE, | 343 | .owner = THIS_MODULE, |
| 382 | .read = ib_uverbs_async_event_read, | 344 | .read = ib_uverbs_async_event_read, |
| 383 | .poll = ib_uverbs_async_event_poll, | 345 | .poll = ib_uverbs_async_event_poll, |
| 384 | .release = ib_uverbs_async_event_close, | 346 | .release = uverbs_uobject_fd_release, |
| 385 | .fasync = ib_uverbs_async_event_fasync, | 347 | .fasync = ib_uverbs_async_event_fasync, |
| 386 | .llseek = no_llseek, | 348 | .llseek = no_llseek, |
| 387 | }; | 349 | }; |
| @@ -491,17 +453,11 @@ static void ib_uverbs_event_handler(struct ib_event_handler *handler, · 103 unmodified lines | |||
| 491 | struct ib_event *event) | 453 | struct ib_event *event) |
| 492 | { | 454 | { |
| 493 | ib_uverbs_async_handler( | 455 | ib_uverbs_async_handler( |
| 494 | container_of(handler, struct ib_uverbs_file, event_handler) | 456 | container_of(handler, struct ib_uverbs_async_event_file, |
| 495 | ->async_file, | 457 | event_handler), |
| 496 | event->element.port_num, event->event, NULL, NULL); | 458 | event->element.port_num, event->event, NULL, NULL); |
| 497 | } | 459 | } |
| 498 | 460 | ||
| 499 | void ib_uverbs_free_async_event_file(struct ib_uverbs_file *file) | ||
| 500 | { | ||
| 501 | kref_put(&file->async_file->ref, ib_uverbs_release_async_event_file); | ||
| 502 | file->async_file = NULL; | ||
| 503 | } | ||
| 504 | |||
| 505 | void ib_uverbs_init_event_queue(struct ib_uverbs_event_queue *ev_queue) | 461 | void ib_uverbs_init_event_queue(struct ib_uverbs_event_queue *ev_queue) |
| 506 | { | 462 | { |
| 507 | spin_lock_init(&ev_queue->lock); | 463 | spin_lock_init(&ev_queue->lock); |
| @@ -511,45 +467,23 @@ void ib_uverbs_init_event_queue(struct ib_uverbs_event_queue *ev_queue) · 3 unmodified lines | |||
| 511 | ev_queue->async_queue = NULL; | 467 | ev_queue->async_queue = NULL; |
| 512 | } | 468 | } |
| 513 | 469 | ||
| 514 | struct file *ib_uverbs_alloc_async_event_file(struct ib_uverbs_file *uverbs_file, | 470 | void ib_uverbs_init_async_event_file( |
| 515 | struct ib_device *ib_dev) | 471 | struct ib_uverbs_async_event_file *async_file) |
| 516 | { | 472 | { |
| 517 | struct ib_uverbs_async_event_file *ev_file; | 473 | struct ib_uverbs_file *uverbs_file = async_file->uobj.ufile; |
| 518 | struct file *filp; | 474 | struct ib_device *ib_dev = async_file->uobj.context->device; |
| 519 | |||
| 520 | ev_file = kzalloc(sizeof(*ev_file), GFP_KERNEL); | ||
| 521 | if (!ev_file) | ||
| 522 | return ERR_PTR(-ENOMEM); | ||
| 523 | |||
| 524 | ib_uverbs_init_event_queue(&ev_file->ev_queue); | ||
| 525 | ev_file->uverbs_file = uverbs_file; | ||
| 526 | kref_get(&ev_file->uverbs_file->ref); | ||
| 527 | kref_init(&ev_file->ref); | ||
| 528 | filp = anon_inode_getfile("[infinibandevent]", &uverbs_async_event_fops, | ||
| 529 | ev_file, O_RDONLY); | ||
| 530 | if (IS_ERR(filp)) | ||
| 531 | goto err_put_refs; | ||
| 532 | |||
| 533 | mutex_lock(&uverbs_file->device->lists_mutex); | ||
| 534 | list_add_tail(&ev_file->list, | ||
| 535 | &uverbs_file->device->uverbs_events_file_list); | ||
| 536 | mutex_unlock(&uverbs_file->device->lists_mutex); | ||
| 537 | |||
| 538 | WARN_ON(uverbs_file->async_file); | ||
| 539 | uverbs_file->async_file = ev_file; | ||
| 540 | kref_get(&uverbs_file->async_file->ref); | ||
| 541 | INIT_IB_EVENT_HANDLER(&uverbs_file->event_handler, | ||
| 542 | ib_dev, | ||
| 543 | ib_uverbs_event_handler); | ||
| 544 | ib_register_event_handler(&uverbs_file->event_handler); | ||
| 545 | /* At that point async file stuff was fully set */ | ||
| 546 | 475 | ||
| 547 | return filp; | 476 | ib_uverbs_init_event_queue(&async_file->ev_queue); |
| 548 | 477 | ||
| 549 | err_put_refs: | 478 | if (!WARN_ON(uverbs_file->async_file)) { |
| 550 | kref_put(&ev_file->uverbs_file->ref, ib_uverbs_release_file); | 479 | uverbs_file->async_file = async_file; |
| 551 | kref_put(&ev_file->ref, ib_uverbs_release_async_event_file); | 480 | /* Pairs with the put in ib_uverbs_release_file */ |
| 552 | return filp; | 481 | uverbs_uobject_get(&async_file->uobj); |
| 482 | } | ||
| 483 | |||
| 484 | INIT_IB_EVENT_HANDLER(&async_file->event_handler, ib_dev, | ||
| 485 | ib_uverbs_event_handler); | ||
| 486 | ib_register_event_handler(&async_file->event_handler); | ||
| 553 | } | 487 | } |
| 554 | 488 | ||
| 555 | static ssize_t verify_hdr(struct ib_uverbs_cmd_hdr *hdr, | 489 | static ssize_t verify_hdr(struct ib_uverbs_cmd_hdr *hdr, |
| @@ -1178,7 +1112,6 @@ static void ib_uverbs_add_one(struct ib_device *device) · 622 unmodified lines | |||
| 1178 | mutex_init(&uverbs_dev->xrcd_tree_mutex); | 1112 | mutex_init(&uverbs_dev->xrcd_tree_mutex); |
| 1179 | mutex_init(&uverbs_dev->lists_mutex); | 1113 | mutex_init(&uverbs_dev->lists_mutex); |
| 1180 | INIT_LIST_HEAD(&uverbs_dev->uverbs_file_list); | 1114 | INIT_LIST_HEAD(&uverbs_dev->uverbs_file_list); |
| 1181 | INIT_LIST_HEAD(&uverbs_dev->uverbs_events_file_list); | ||
| 1182 | rcu_assign_pointer(uverbs_dev->ib_dev, device); | 1115 | rcu_assign_pointer(uverbs_dev->ib_dev, device); |
| 1183 | uverbs_dev->num_comp_vectors = device->num_comp_vectors; | 1116 | uverbs_dev->num_comp_vectors = device->num_comp_vectors; |
| 1184 | 1117 | ||
| @@ -1223,7 +1156,6 @@ static void ib_uverbs_free_hw_resources(struct ib_uverbs_device *uverbs_dev, · 38 unmodified lines | |||
| 1223 | struct ib_device *ib_dev) | 1156 | struct ib_device *ib_dev) |
| 1224 | { | 1157 | { |
| 1225 | struct ib_uverbs_file *file; | 1158 | struct ib_uverbs_file *file; |
| 1226 | struct ib_uverbs_async_event_file *event_file; | ||
| 1227 | struct ib_event event; | 1159 | struct ib_event event; |
| 1228 | 1160 | ||
| 1229 | /* Pending running commands to terminate */ | 1161 | /* Pending running commands to terminate */ |
| @@ -1246,31 +1178,15 @@ static void ib_uverbs_free_hw_resources(struct ib_uverbs_device *uverbs_dev, · 16 unmodified lines | |||
| 1246 | */ | 1178 | */ |
| 1247 | mutex_unlock(&uverbs_dev->lists_mutex); | 1179 | mutex_unlock(&uverbs_dev->lists_mutex); |
| 1248 | 1180 | ||
| 1249 | ib_uverbs_event_handler(&file->event_handler, &event); | 1181 | if (file->async_file) |
| 1182 | ib_uverbs_event_handler( | ||
| 1183 | &file->async_file->event_handler, &event); | ||
| 1184 | |||
| 1250 | uverbs_destroy_ufile_hw(file, RDMA_REMOVE_DRIVER_REMOVE); | 1185 | uverbs_destroy_ufile_hw(file, RDMA_REMOVE_DRIVER_REMOVE); |
| 1251 | kref_put(&file->ref, ib_uverbs_release_file); | 1186 | kref_put(&file->ref, ib_uverbs_release_file); |
| 1252 | 1187 | ||
| 1253 | mutex_lock(&uverbs_dev->lists_mutex); | 1188 | mutex_lock(&uverbs_dev->lists_mutex); |
| 1254 | } | 1189 | } |
| 1255 | |||
| 1256 | while (!list_empty(&uverbs_dev->uverbs_events_file_list)) { | ||
| 1257 | event_file = list_first_entry(&uverbs_dev-> | ||
| 1258 | uverbs_events_file_list, | ||
| 1259 | struct ib_uverbs_async_event_file, | ||
| 1260 | list); | ||
| 1261 | spin_lock_irq(&event_file->ev_queue.lock); | ||
| 1262 | event_file->ev_queue.is_closed = 1; | ||
| 1263 | spin_unlock_irq(&event_file->ev_queue.lock); | ||
| 1264 | |||
| 1265 | list_del(&event_file->list); | ||
| 1266 | ib_unregister_event_handler( | ||
| 1267 | &event_file->uverbs_file->event_handler); | ||
| 1268 | event_file->uverbs_file->event_handler.device = | ||
| 1269 | NULL; | ||
| 1270 | |||
| 1271 | wake_up_interruptible(&event_file->ev_queue.poll_wait); | ||
| 1272 | kill_fasync(&event_file->ev_queue.async_queue, SIGIO, POLL_IN); | ||
| 1273 | } | ||
| 1274 | mutex_unlock(&uverbs_dev->lists_mutex); | 1190 | mutex_unlock(&uverbs_dev->lists_mutex); |
| 1275 | 1191 | ||
| 1276 | uverbs_disassociate_api(uverbs_dev->uapi); | 1192 | uverbs_disassociate_api(uverbs_dev->uapi); |
| @@ -202,17 +202,15 @@ static int uverbs_free_pd(struct ib_uobject *uobject, · 201 unmodified lines | |||
| 202 | return 0; | 202 | return 0; |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | static int | 205 | void ib_uverbs_free_event_queue(struct ib_uverbs_event_queue *event_queue) |
| 206 | uverbs_completion_event_file_destroy_uobj(struct ib_uobject *uobj, | ||
| 207 | enum rdma_remove_reason why) | ||
| 208 | { | 206 | { |
| 209 | struct ib_uverbs_completion_event_file *file = | ||
| 210 | container_of(uobj, struct ib_uverbs_completion_event_file, | ||
| 211 | uobj); | ||
| 212 | struct ib_uverbs_event_queue *event_queue = &file->ev_queue; | ||
| 213 | struct ib_uverbs_event *entry, *tmp; | 207 | struct ib_uverbs_event *entry, *tmp; |
| 214 | 208 | ||
| 215 | spin_lock_irq(&event_queue->lock); | 209 | spin_lock_irq(&event_queue->lock); |
| 210 | /* | ||
| 211 | * The user must ensure that no new items are added to the event_list | ||
| 212 | * once is_closed is set. | ||
| 213 | */ | ||
| 216 | event_queue->is_closed = 1; | 214 | event_queue->is_closed = 1; |
| 217 | spin_unlock_irq(&event_queue->lock); | 215 | spin_unlock_irq(&event_queue->lock); |
| 218 | wake_up_interruptible(&event_queue->poll_wait); | 216 | wake_up_interruptible(&event_queue->poll_wait); |
| @@ -225,8 +223,19 @@ uverbs_completion_event_file_destroy_uobj(struct ib_uobject *uobj, · 6 unmodified lines | |||
| 225 | kfree(entry); | 223 | kfree(entry); |
| 226 | } | 224 | } |
| 227 | spin_unlock_irq(&event_queue->lock); | 225 | spin_unlock_irq(&event_queue->lock); |
| 226 | } | ||
| 227 | |||
| 228 | static int | ||
| 229 | uverbs_completion_event_file_destroy_uobj(struct ib_uobject *uobj, | ||
| 230 | enum rdma_remove_reason why) | ||
| 231 | { | ||
| 232 | struct ib_uverbs_completion_event_file *file = | ||
| 233 | container_of(uobj, struct ib_uverbs_completion_event_file, | ||
| 234 | uobj); | ||
| 235 | |||
| 236 | ib_uverbs_free_event_queue(&file->ev_queue); | ||
| 228 | return 0; | 237 | return 0; |
| 229 | }; | 238 | } |
| 230 | 239 | ||
| 231 | int uverbs_destroy_def_handler(struct uverbs_attr_bundle *attrs) | 240 | int uverbs_destroy_def_handler(struct uverbs_attr_bundle *attrs) |
| 232 | { | 241 | { |
| @@ -0,0 +1,33 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB | ||
| 2 | /* | ||
| 3 | * Copyright (c) 2019, Mellanox Technologies inc. All rights reserved. | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <rdma/uverbs_std_types.h> | ||
| 7 | #include <rdma/uverbs_ioctl.h> | ||
| 8 | #include "rdma_core.h" | ||
| 9 | #include "uverbs.h" | ||
| 10 | |||
| 11 | static int uverbs_async_event_destroy_uobj(struct ib_uobject *uobj, | ||
| 12 | enum rdma_remove_reason why) | ||
| 13 | { | ||
| 14 | struct ib_uverbs_async_event_file *event_file = | ||
| 15 | container_of(uobj, struct ib_uverbs_async_event_file, uobj); | ||
| 16 | |||
| 17 | ib_unregister_event_handler(&event_file->event_handler); | ||
| 18 | ib_uverbs_free_event_queue(&event_file->ev_queue); | ||
| 19 | return 0; | ||
| 20 | } | ||
| 21 | |||
| 22 | DECLARE_UVERBS_NAMED_OBJECT( | ||
| 23 | UVERBS_OBJECT_ASYNC_EVENT, | ||
| 24 | UVERBS_TYPE_ALLOC_FD(sizeof(struct ib_uverbs_async_event_file), | ||
| 25 | uverbs_async_event_destroy_uobj, | ||
| 26 | &uverbs_async_event_fops, | ||
| 27 | "[infinibandevent]", | ||
| 28 | O_RDONLY)); | ||
| 29 | |||
| 30 | const struct uapi_definition uverbs_def_obj_async_fd[] = { | ||
| 31 | UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_ASYNC_EVENT), | ||
| 32 | {} | ||
| 33 | }; | ||
| @@ -626,6 +626,7 @@ void uverbs_destroy_api(struct uverbs_api *uapi) · 625 unmodified lines | |||
| 626 | } | 626 | } |
| 627 | 627 | ||
| 628 | static const struct uapi_definition uverbs_core_api[] = { | 628 | static const struct uapi_definition uverbs_core_api[] = { |
| 629 | UAPI_DEF_CHAIN(uverbs_def_obj_async_fd), | ||
| 629 | UAPI_DEF_CHAIN(uverbs_def_obj_counters), | 630 | UAPI_DEF_CHAIN(uverbs_def_obj_counters), |
| 630 | UAPI_DEF_CHAIN(uverbs_def_obj_cq), | 631 | UAPI_DEF_CHAIN(uverbs_def_obj_cq), |
| 631 | UAPI_DEF_CHAIN(uverbs_def_obj_device), | 632 | UAPI_DEF_CHAIN(uverbs_def_obj_device), |
| @@ -56,6 +56,7 @@ enum uverbs_default_objects { · 55 unmodified lines | |||
| 56 | UVERBS_OBJECT_FLOW_ACTION, | 56 | UVERBS_OBJECT_FLOW_ACTION, |
| 57 | UVERBS_OBJECT_DM, | 57 | UVERBS_OBJECT_DM, |
| 58 | UVERBS_OBJECT_COUNTERS, | 58 | UVERBS_OBJECT_COUNTERS, |
| 59 | UVERBS_OBJECT_ASYNC_EVENT, | ||
| 59 | }; | 60 | }; |
| 60 | 61 | ||
| 61 | enum { | 62 | enum { |