diff options
-rw-r--r-- | drivers/infiniband/core/uverbs.h | 1 | ||||
-rw-r--r-- | drivers/infiniband/core/uverbs_cmd.c | 120 | ||||
-rw-r--r-- | drivers/infiniband/core/uverbs_main.c | 27 | ||||
-rw-r--r-- | include/rdma/ib_verbs.h | 1 |
4 files changed, 86 insertions, 63 deletions
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index b1897bed14ad..cc124344dd2c 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h | |||
@@ -69,6 +69,7 @@ struct ib_uverbs_event_file { | |||
69 | 69 | ||
70 | struct ib_uverbs_file { | 70 | struct ib_uverbs_file { |
71 | struct kref ref; | 71 | struct kref ref; |
72 | struct semaphore mutex; | ||
72 | struct ib_uverbs_device *device; | 73 | struct ib_uverbs_device *device; |
73 | struct ib_ucontext *ucontext; | 74 | struct ib_ucontext *ucontext; |
74 | struct ib_event_handler event_handler; | 75 | struct ib_event_handler event_handler; |
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index e91ebde46481..562445165d2b 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c | |||
@@ -76,8 +76,9 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, | |||
76 | struct ib_uverbs_get_context_resp resp; | 76 | struct ib_uverbs_get_context_resp resp; |
77 | struct ib_udata udata; | 77 | struct ib_udata udata; |
78 | struct ib_device *ibdev = file->device->ib_dev; | 78 | struct ib_device *ibdev = file->device->ib_dev; |
79 | struct ib_ucontext *ucontext; | ||
79 | int i; | 80 | int i; |
80 | int ret = in_len; | 81 | int ret; |
81 | 82 | ||
82 | if (out_len < sizeof resp) | 83 | if (out_len < sizeof resp) |
83 | return -ENOSPC; | 84 | return -ENOSPC; |
@@ -85,45 +86,56 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, | |||
85 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 86 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
86 | return -EFAULT; | 87 | return -EFAULT; |
87 | 88 | ||
89 | down(&file->mutex); | ||
90 | |||
91 | if (file->ucontext) { | ||
92 | ret = -EINVAL; | ||
93 | goto err; | ||
94 | } | ||
95 | |||
88 | INIT_UDATA(&udata, buf + sizeof cmd, | 96 | INIT_UDATA(&udata, buf + sizeof cmd, |
89 | (unsigned long) cmd.response + sizeof resp, | 97 | (unsigned long) cmd.response + sizeof resp, |
90 | in_len - sizeof cmd, out_len - sizeof resp); | 98 | in_len - sizeof cmd, out_len - sizeof resp); |
91 | 99 | ||
92 | file->ucontext = ibdev->alloc_ucontext(ibdev, &udata); | 100 | ucontext = ibdev->alloc_ucontext(ibdev, &udata); |
93 | if (IS_ERR(file->ucontext)) { | 101 | if (IS_ERR(ucontext)) |
94 | ret = PTR_ERR(file->ucontext); | 102 | return PTR_ERR(file->ucontext); |
95 | file->ucontext = NULL; | ||
96 | return ret; | ||
97 | } | ||
98 | 103 | ||
99 | file->ucontext->device = ibdev; | 104 | ucontext->device = ibdev; |
100 | INIT_LIST_HEAD(&file->ucontext->pd_list); | 105 | INIT_LIST_HEAD(&ucontext->pd_list); |
101 | INIT_LIST_HEAD(&file->ucontext->mr_list); | 106 | INIT_LIST_HEAD(&ucontext->mr_list); |
102 | INIT_LIST_HEAD(&file->ucontext->mw_list); | 107 | INIT_LIST_HEAD(&ucontext->mw_list); |
103 | INIT_LIST_HEAD(&file->ucontext->cq_list); | 108 | INIT_LIST_HEAD(&ucontext->cq_list); |
104 | INIT_LIST_HEAD(&file->ucontext->qp_list); | 109 | INIT_LIST_HEAD(&ucontext->qp_list); |
105 | INIT_LIST_HEAD(&file->ucontext->srq_list); | 110 | INIT_LIST_HEAD(&ucontext->srq_list); |
106 | INIT_LIST_HEAD(&file->ucontext->ah_list); | 111 | INIT_LIST_HEAD(&ucontext->ah_list); |
107 | spin_lock_init(&file->ucontext->lock); | ||
108 | 112 | ||
109 | resp.async_fd = file->async_file.fd; | 113 | resp.async_fd = file->async_file.fd; |
110 | for (i = 0; i < file->device->num_comp; ++i) | 114 | for (i = 0; i < file->device->num_comp; ++i) |
111 | if (copy_to_user((void __user *) (unsigned long) cmd.cq_fd_tab + | 115 | if (copy_to_user((void __user *) (unsigned long) cmd.cq_fd_tab + |
112 | i * sizeof (__u32), | 116 | i * sizeof (__u32), |
113 | &file->comp_file[i].fd, sizeof (__u32))) | 117 | &file->comp_file[i].fd, sizeof (__u32))) { |
114 | goto err; | 118 | ret = -EFAULT; |
119 | goto err_free; | ||
120 | } | ||
115 | 121 | ||
116 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 122 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
117 | &resp, sizeof resp)) | 123 | &resp, sizeof resp)) { |
118 | goto err; | 124 | ret = -EFAULT; |
125 | goto err_free; | ||
126 | } | ||
127 | |||
128 | file->ucontext = ucontext; | ||
129 | up(&file->mutex); | ||
119 | 130 | ||
120 | return in_len; | 131 | return in_len; |
121 | 132 | ||
122 | err: | 133 | err_free: |
123 | ibdev->dealloc_ucontext(file->ucontext); | 134 | ibdev->dealloc_ucontext(ucontext); |
124 | file->ucontext = NULL; | ||
125 | 135 | ||
126 | return -EFAULT; | 136 | err: |
137 | up(&file->mutex); | ||
138 | return ret; | ||
127 | } | 139 | } |
128 | 140 | ||
129 | ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file, | 141 | ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file, |
@@ -352,9 +364,9 @@ retry: | |||
352 | if (ret) | 364 | if (ret) |
353 | goto err_pd; | 365 | goto err_pd; |
354 | 366 | ||
355 | spin_lock_irq(&file->ucontext->lock); | 367 | down(&file->mutex); |
356 | list_add_tail(&uobj->list, &file->ucontext->pd_list); | 368 | list_add_tail(&uobj->list, &file->ucontext->pd_list); |
357 | spin_unlock_irq(&file->ucontext->lock); | 369 | up(&file->mutex); |
358 | 370 | ||
359 | memset(&resp, 0, sizeof resp); | 371 | memset(&resp, 0, sizeof resp); |
360 | resp.pd_handle = uobj->id; | 372 | resp.pd_handle = uobj->id; |
@@ -368,9 +380,9 @@ retry: | |||
368 | return in_len; | 380 | return in_len; |
369 | 381 | ||
370 | err_list: | 382 | err_list: |
371 | spin_lock_irq(&file->ucontext->lock); | 383 | down(&file->mutex); |
372 | list_del(&uobj->list); | 384 | list_del(&uobj->list); |
373 | spin_unlock_irq(&file->ucontext->lock); | 385 | up(&file->mutex); |
374 | 386 | ||
375 | down(&ib_uverbs_idr_mutex); | 387 | down(&ib_uverbs_idr_mutex); |
376 | idr_remove(&ib_uverbs_pd_idr, uobj->id); | 388 | idr_remove(&ib_uverbs_pd_idr, uobj->id); |
@@ -410,9 +422,9 @@ ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file, | |||
410 | 422 | ||
411 | idr_remove(&ib_uverbs_pd_idr, cmd.pd_handle); | 423 | idr_remove(&ib_uverbs_pd_idr, cmd.pd_handle); |
412 | 424 | ||
413 | spin_lock_irq(&file->ucontext->lock); | 425 | down(&file->mutex); |
414 | list_del(&uobj->list); | 426 | list_del(&uobj->list); |
415 | spin_unlock_irq(&file->ucontext->lock); | 427 | up(&file->mutex); |
416 | 428 | ||
417 | kfree(uobj); | 429 | kfree(uobj); |
418 | 430 | ||
@@ -512,9 +524,9 @@ retry: | |||
512 | 524 | ||
513 | resp.mr_handle = obj->uobject.id; | 525 | resp.mr_handle = obj->uobject.id; |
514 | 526 | ||
515 | spin_lock_irq(&file->ucontext->lock); | 527 | down(&file->mutex); |
516 | list_add_tail(&obj->uobject.list, &file->ucontext->mr_list); | 528 | list_add_tail(&obj->uobject.list, &file->ucontext->mr_list); |
517 | spin_unlock_irq(&file->ucontext->lock); | 529 | up(&file->mutex); |
518 | 530 | ||
519 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 531 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
520 | &resp, sizeof resp)) { | 532 | &resp, sizeof resp)) { |
@@ -527,9 +539,9 @@ retry: | |||
527 | return in_len; | 539 | return in_len; |
528 | 540 | ||
529 | err_list: | 541 | err_list: |
530 | spin_lock_irq(&file->ucontext->lock); | 542 | down(&file->mutex); |
531 | list_del(&obj->uobject.list); | 543 | list_del(&obj->uobject.list); |
532 | spin_unlock_irq(&file->ucontext->lock); | 544 | up(&file->mutex); |
533 | 545 | ||
534 | err_unreg: | 546 | err_unreg: |
535 | ib_dereg_mr(mr); | 547 | ib_dereg_mr(mr); |
@@ -570,9 +582,9 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file, | |||
570 | 582 | ||
571 | idr_remove(&ib_uverbs_mr_idr, cmd.mr_handle); | 583 | idr_remove(&ib_uverbs_mr_idr, cmd.mr_handle); |
572 | 584 | ||
573 | spin_lock_irq(&file->ucontext->lock); | 585 | down(&file->mutex); |
574 | list_del(&memobj->uobject.list); | 586 | list_del(&memobj->uobject.list); |
575 | spin_unlock_irq(&file->ucontext->lock); | 587 | up(&file->mutex); |
576 | 588 | ||
577 | ib_umem_release(file->device->ib_dev, &memobj->umem); | 589 | ib_umem_release(file->device->ib_dev, &memobj->umem); |
578 | kfree(memobj); | 590 | kfree(memobj); |
@@ -647,9 +659,9 @@ retry: | |||
647 | if (ret) | 659 | if (ret) |
648 | goto err_cq; | 660 | goto err_cq; |
649 | 661 | ||
650 | spin_lock_irq(&file->ucontext->lock); | 662 | down(&file->mutex); |
651 | list_add_tail(&uobj->uobject.list, &file->ucontext->cq_list); | 663 | list_add_tail(&uobj->uobject.list, &file->ucontext->cq_list); |
652 | spin_unlock_irq(&file->ucontext->lock); | 664 | up(&file->mutex); |
653 | 665 | ||
654 | memset(&resp, 0, sizeof resp); | 666 | memset(&resp, 0, sizeof resp); |
655 | resp.cq_handle = uobj->uobject.id; | 667 | resp.cq_handle = uobj->uobject.id; |
@@ -664,9 +676,9 @@ retry: | |||
664 | return in_len; | 676 | return in_len; |
665 | 677 | ||
666 | err_list: | 678 | err_list: |
667 | spin_lock_irq(&file->ucontext->lock); | 679 | down(&file->mutex); |
668 | list_del(&uobj->uobject.list); | 680 | list_del(&uobj->uobject.list); |
669 | spin_unlock_irq(&file->ucontext->lock); | 681 | up(&file->mutex); |
670 | 682 | ||
671 | down(&ib_uverbs_idr_mutex); | 683 | down(&ib_uverbs_idr_mutex); |
672 | idr_remove(&ib_uverbs_cq_idr, uobj->uobject.id); | 684 | idr_remove(&ib_uverbs_cq_idr, uobj->uobject.id); |
@@ -712,9 +724,9 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, | |||
712 | 724 | ||
713 | idr_remove(&ib_uverbs_cq_idr, cmd.cq_handle); | 725 | idr_remove(&ib_uverbs_cq_idr, cmd.cq_handle); |
714 | 726 | ||
715 | spin_lock_irq(&file->ucontext->lock); | 727 | down(&file->mutex); |
716 | list_del(&uobj->uobject.list); | 728 | list_del(&uobj->uobject.list); |
717 | spin_unlock_irq(&file->ucontext->lock); | 729 | up(&file->mutex); |
718 | 730 | ||
719 | spin_lock_irq(&file->comp_file[0].lock); | 731 | spin_lock_irq(&file->comp_file[0].lock); |
720 | list_for_each_entry_safe(evt, tmp, &uobj->comp_list, obj_list) { | 732 | list_for_each_entry_safe(evt, tmp, &uobj->comp_list, obj_list) { |
@@ -847,9 +859,9 @@ retry: | |||
847 | 859 | ||
848 | resp.qp_handle = uobj->uobject.id; | 860 | resp.qp_handle = uobj->uobject.id; |
849 | 861 | ||
850 | spin_lock_irq(&file->ucontext->lock); | 862 | down(&file->mutex); |
851 | list_add_tail(&uobj->uobject.list, &file->ucontext->qp_list); | 863 | list_add_tail(&uobj->uobject.list, &file->ucontext->qp_list); |
852 | spin_unlock_irq(&file->ucontext->lock); | 864 | up(&file->mutex); |
853 | 865 | ||
854 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 866 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
855 | &resp, sizeof resp)) { | 867 | &resp, sizeof resp)) { |
@@ -862,9 +874,9 @@ retry: | |||
862 | return in_len; | 874 | return in_len; |
863 | 875 | ||
864 | err_list: | 876 | err_list: |
865 | spin_lock_irq(&file->ucontext->lock); | 877 | down(&file->mutex); |
866 | list_del(&uobj->uobject.list); | 878 | list_del(&uobj->uobject.list); |
867 | spin_unlock_irq(&file->ucontext->lock); | 879 | up(&file->mutex); |
868 | 880 | ||
869 | err_destroy: | 881 | err_destroy: |
870 | ib_destroy_qp(qp); | 882 | ib_destroy_qp(qp); |
@@ -989,9 +1001,9 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, | |||
989 | 1001 | ||
990 | idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle); | 1002 | idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle); |
991 | 1003 | ||
992 | spin_lock_irq(&file->ucontext->lock); | 1004 | down(&file->mutex); |
993 | list_del(&uobj->uobject.list); | 1005 | list_del(&uobj->uobject.list); |
994 | spin_unlock_irq(&file->ucontext->lock); | 1006 | up(&file->mutex); |
995 | 1007 | ||
996 | spin_lock_irq(&file->async_file.lock); | 1008 | spin_lock_irq(&file->async_file.lock); |
997 | list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { | 1009 | list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { |
@@ -1136,9 +1148,9 @@ retry: | |||
1136 | 1148 | ||
1137 | resp.srq_handle = uobj->uobject.id; | 1149 | resp.srq_handle = uobj->uobject.id; |
1138 | 1150 | ||
1139 | spin_lock_irq(&file->ucontext->lock); | 1151 | down(&file->mutex); |
1140 | list_add_tail(&uobj->uobject.list, &file->ucontext->srq_list); | 1152 | list_add_tail(&uobj->uobject.list, &file->ucontext->srq_list); |
1141 | spin_unlock_irq(&file->ucontext->lock); | 1153 | up(&file->mutex); |
1142 | 1154 | ||
1143 | if (copy_to_user((void __user *) (unsigned long) cmd.response, | 1155 | if (copy_to_user((void __user *) (unsigned long) cmd.response, |
1144 | &resp, sizeof resp)) { | 1156 | &resp, sizeof resp)) { |
@@ -1151,9 +1163,9 @@ retry: | |||
1151 | return in_len; | 1163 | return in_len; |
1152 | 1164 | ||
1153 | err_list: | 1165 | err_list: |
1154 | spin_lock_irq(&file->ucontext->lock); | 1166 | down(&file->mutex); |
1155 | list_del(&uobj->uobject.list); | 1167 | list_del(&uobj->uobject.list); |
1156 | spin_unlock_irq(&file->ucontext->lock); | 1168 | up(&file->mutex); |
1157 | 1169 | ||
1158 | err_destroy: | 1170 | err_destroy: |
1159 | ib_destroy_srq(srq); | 1171 | ib_destroy_srq(srq); |
@@ -1227,9 +1239,9 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, | |||
1227 | 1239 | ||
1228 | idr_remove(&ib_uverbs_srq_idr, cmd.srq_handle); | 1240 | idr_remove(&ib_uverbs_srq_idr, cmd.srq_handle); |
1229 | 1241 | ||
1230 | spin_lock_irq(&file->ucontext->lock); | 1242 | down(&file->mutex); |
1231 | list_del(&uobj->uobject.list); | 1243 | list_del(&uobj->uobject.list); |
1232 | spin_unlock_irq(&file->ucontext->lock); | 1244 | up(&file->mutex); |
1233 | 1245 | ||
1234 | spin_lock_irq(&file->async_file.lock); | 1246 | spin_lock_irq(&file->async_file.lock); |
1235 | list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { | 1247 | list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { |
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index ce5bdb7af306..12511808de21 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c | |||
@@ -448,7 +448,9 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, | |||
448 | if (hdr.in_words * 4 != count) | 448 | if (hdr.in_words * 4 != count) |
449 | return -EINVAL; | 449 | return -EINVAL; |
450 | 450 | ||
451 | if (hdr.command < 0 || hdr.command >= ARRAY_SIZE(uverbs_cmd_table)) | 451 | if (hdr.command < 0 || |
452 | hdr.command >= ARRAY_SIZE(uverbs_cmd_table) || | ||
453 | !uverbs_cmd_table[hdr.command]) | ||
452 | return -EINVAL; | 454 | return -EINVAL; |
453 | 455 | ||
454 | if (!file->ucontext && | 456 | if (!file->ucontext && |
@@ -484,27 +486,29 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp) | |||
484 | file = kmalloc(sizeof *file + | 486 | file = kmalloc(sizeof *file + |
485 | (dev->num_comp - 1) * sizeof (struct ib_uverbs_event_file), | 487 | (dev->num_comp - 1) * sizeof (struct ib_uverbs_event_file), |
486 | GFP_KERNEL); | 488 | GFP_KERNEL); |
487 | if (!file) | 489 | if (!file) { |
488 | return -ENOMEM; | 490 | ret = -ENOMEM; |
491 | goto err; | ||
492 | } | ||
489 | 493 | ||
490 | file->device = dev; | 494 | file->device = dev; |
491 | kref_init(&file->ref); | 495 | kref_init(&file->ref); |
496 | init_MUTEX(&file->mutex); | ||
492 | 497 | ||
493 | file->ucontext = NULL; | 498 | file->ucontext = NULL; |
494 | 499 | ||
500 | kref_get(&file->ref); | ||
495 | ret = ib_uverbs_event_init(&file->async_file, file); | 501 | ret = ib_uverbs_event_init(&file->async_file, file); |
496 | if (ret) | 502 | if (ret) |
497 | goto err; | 503 | goto err_kref; |
498 | 504 | ||
499 | file->async_file.is_async = 1; | 505 | file->async_file.is_async = 1; |
500 | 506 | ||
501 | kref_get(&file->ref); | ||
502 | |||
503 | for (i = 0; i < dev->num_comp; ++i) { | 507 | for (i = 0; i < dev->num_comp; ++i) { |
508 | kref_get(&file->ref); | ||
504 | ret = ib_uverbs_event_init(&file->comp_file[i], file); | 509 | ret = ib_uverbs_event_init(&file->comp_file[i], file); |
505 | if (ret) | 510 | if (ret) |
506 | goto err_async; | 511 | goto err_async; |
507 | kref_get(&file->ref); | ||
508 | file->comp_file[i].is_async = 0; | 512 | file->comp_file[i].is_async = 0; |
509 | } | 513 | } |
510 | 514 | ||
@@ -524,9 +528,16 @@ err_async: | |||
524 | 528 | ||
525 | ib_uverbs_event_release(&file->async_file); | 529 | ib_uverbs_event_release(&file->async_file); |
526 | 530 | ||
527 | err: | 531 | err_kref: |
532 | /* | ||
533 | * One extra kref_put() because we took a reference before the | ||
534 | * event file creation that failed and got us here. | ||
535 | */ | ||
536 | kref_put(&file->ref, ib_uverbs_release_file); | ||
528 | kref_put(&file->ref, ib_uverbs_release_file); | 537 | kref_put(&file->ref, ib_uverbs_release_file); |
529 | 538 | ||
539 | err: | ||
540 | module_put(dev->ib_dev->owner); | ||
530 | return ret; | 541 | return ret; |
531 | } | 542 | } |
532 | 543 | ||
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index e16cf94870f2..e6f4c9e55df7 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h | |||
@@ -665,7 +665,6 @@ struct ib_ucontext { | |||
665 | struct list_head qp_list; | 665 | struct list_head qp_list; |
666 | struct list_head srq_list; | 666 | struct list_head srq_list; |
667 | struct list_head ah_list; | 667 | struct list_head ah_list; |
668 | spinlock_t lock; | ||
669 | }; | 668 | }; |
670 | 669 | ||
671 | struct ib_uobject { | 670 | struct ib_uobject { |