diff options
author | Roland Dreier <rolandd@cisco.com> | 2005-10-28 18:38:26 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2005-10-28 18:38:26 -0400 |
commit | 70a30e16a8a9d22396a4d1e96af86e43594df584 (patch) | |
tree | 0d8582567c62f7929620ec03128c79f9d8c65a58 | |
parent | a74968f8c3b1166cfe0942901b56165f06ab6f60 (diff) |
[IB] uverbs: Fix device lifetime problems
Move ib_uverbs module to using cdev_alloc() and class_device_create()
so that we can handle device lifetime properly. Now we can make sure
we keep all of our data structures around until the last way to reach
them is gone.
Signed-off-by: Roland Dreier <rolandd@cisco.com>
-rw-r--r-- | drivers/infiniband/core/uverbs.h | 36 | ||||
-rw-r--r-- | drivers/infiniband/core/uverbs_cmd.c | 38 | ||||
-rw-r--r-- | drivers/infiniband/core/uverbs_main.c | 203 |
3 files changed, 182 insertions, 95 deletions
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 63c8085c0c98..031cdf3c066d 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h | |||
@@ -39,20 +39,38 @@ | |||
39 | #ifndef UVERBS_H | 39 | #ifndef UVERBS_H |
40 | #define UVERBS_H | 40 | #define UVERBS_H |
41 | 41 | ||
42 | /* Include device.h and fs.h until cdev.h is self-sufficient */ | ||
43 | #include <linux/fs.h> | ||
44 | #include <linux/device.h> | ||
45 | #include <linux/cdev.h> | ||
46 | #include <linux/kref.h> | 42 | #include <linux/kref.h> |
47 | #include <linux/idr.h> | 43 | #include <linux/idr.h> |
48 | 44 | ||
49 | #include <rdma/ib_verbs.h> | 45 | #include <rdma/ib_verbs.h> |
50 | #include <rdma/ib_user_verbs.h> | 46 | #include <rdma/ib_user_verbs.h> |
51 | 47 | ||
48 | /* | ||
49 | * Our lifetime rules for these structs are the following: | ||
50 | * | ||
51 | * struct ib_uverbs_device: One reference is held by the module and | ||
52 | * released in ib_uverbs_remove_one(). Another reference is taken by | ||
53 | * ib_uverbs_open() each time the character special file is opened, | ||
54 | * and released in ib_uverbs_release_file() when the file is released. | ||
55 | * | ||
56 | * struct ib_uverbs_file: One reference is held by the VFS and | ||
57 | * released when the file is closed. Another reference is taken when | ||
58 | * an asynchronous event queue file is created and released when the | ||
59 | * event file is closed. | ||
60 | * | ||
61 | * struct ib_uverbs_event_file: One reference is held by the VFS and | ||
62 | * released when the file is closed. For asynchronous event files, | ||
63 | * another reference is held by the corresponding main context file | ||
64 | * and released when that file is closed. For completion event files, | ||
65 | * a reference is taken when a CQ is created that uses the file, and | ||
66 | * released when the CQ is destroyed. | ||
67 | */ | ||
68 | |||
52 | struct ib_uverbs_device { | 69 | struct ib_uverbs_device { |
70 | struct kref ref; | ||
53 | int devnum; | 71 | int devnum; |
54 | struct cdev dev; | 72 | struct cdev *dev; |
55 | struct class_device class_dev; | 73 | struct class_device *class_dev; |
56 | struct ib_device *ib_dev; | 74 | struct ib_device *ib_dev; |
57 | int num_comp_vectors; | 75 | int num_comp_vectors; |
58 | }; | 76 | }; |
@@ -115,6 +133,12 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, | |||
115 | void ib_uverbs_release_event_file(struct kref *ref); | 133 | void ib_uverbs_release_event_file(struct kref *ref); |
116 | struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd); | 134 | struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd); |
117 | 135 | ||
136 | void ib_uverbs_release_ucq(struct ib_uverbs_file *file, | ||
137 | struct ib_uverbs_event_file *ev_file, | ||
138 | struct ib_ucq_object *uobj); | ||
139 | void ib_uverbs_release_uevent(struct ib_uverbs_file *file, | ||
140 | struct ib_uevent_object *uobj); | ||
141 | |||
118 | void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context); | 142 | void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context); |
119 | void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr); | 143 | void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr); |
120 | void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr); | 144 | void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr); |
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 14583bb6e2c0..8c89abc8c764 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c | |||
@@ -35,6 +35,7 @@ | |||
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include <linux/file.h> | 37 | #include <linux/file.h> |
38 | #include <linux/fs.h> | ||
38 | 39 | ||
39 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
40 | 41 | ||
@@ -114,7 +115,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, | |||
114 | 115 | ||
115 | kref_get(&file->async_file->ref); | 116 | kref_get(&file->async_file->ref); |
116 | kref_get(&file->ref); | 117 | kref_get(&file->ref); |
117 | file->ucontext = ucontext; | 118 | file->ucontext = ucontext; |
118 | 119 | ||
119 | fd_install(resp.async_fd, filp); | 120 | fd_install(resp.async_fd, filp); |
120 | 121 | ||
@@ -761,7 +762,6 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, | |||
761 | struct ib_cq *cq; | 762 | struct ib_cq *cq; |
762 | struct ib_ucq_object *uobj; | 763 | struct ib_ucq_object *uobj; |
763 | struct ib_uverbs_event_file *ev_file; | 764 | struct ib_uverbs_event_file *ev_file; |
764 | struct ib_uverbs_event *evt, *tmp; | ||
765 | u64 user_handle; | 765 | u64 user_handle; |
766 | int ret = -EINVAL; | 766 | int ret = -EINVAL; |
767 | 767 | ||
@@ -790,23 +790,7 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, | |||
790 | list_del(&uobj->uobject.list); | 790 | list_del(&uobj->uobject.list); |
791 | up(&file->mutex); | 791 | up(&file->mutex); |
792 | 792 | ||
793 | if (ev_file) { | 793 | ib_uverbs_release_ucq(file, ev_file, uobj); |
794 | spin_lock_irq(&ev_file->lock); | ||
795 | list_for_each_entry_safe(evt, tmp, &uobj->comp_list, obj_list) { | ||
796 | list_del(&evt->list); | ||
797 | kfree(evt); | ||
798 | } | ||
799 | spin_unlock_irq(&ev_file->lock); | ||
800 | |||
801 | kref_put(&ev_file->ref, ib_uverbs_release_event_file); | ||
802 | } | ||
803 | |||
804 | spin_lock_irq(&file->async_file->lock); | ||
805 | list_for_each_entry_safe(evt, tmp, &uobj->async_list, obj_list) { | ||
806 | list_del(&evt->list); | ||
807 | kfree(evt); | ||
808 | } | ||
809 | spin_unlock_irq(&file->async_file->lock); | ||
810 | 794 | ||
811 | resp.comp_events_reported = uobj->comp_events_reported; | 795 | resp.comp_events_reported = uobj->comp_events_reported; |
812 | resp.async_events_reported = uobj->async_events_reported; | 796 | resp.async_events_reported = uobj->async_events_reported; |
@@ -1043,7 +1027,6 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, | |||
1043 | struct ib_uverbs_destroy_qp_resp resp; | 1027 | struct ib_uverbs_destroy_qp_resp resp; |
1044 | struct ib_qp *qp; | 1028 | struct ib_qp *qp; |
1045 | struct ib_uevent_object *uobj; | 1029 | struct ib_uevent_object *uobj; |
1046 | struct ib_uverbs_event *evt, *tmp; | ||
1047 | int ret = -EINVAL; | 1030 | int ret = -EINVAL; |
1048 | 1031 | ||
1049 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 1032 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
@@ -1069,12 +1052,7 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, | |||
1069 | list_del(&uobj->uobject.list); | 1052 | list_del(&uobj->uobject.list); |
1070 | up(&file->mutex); | 1053 | up(&file->mutex); |
1071 | 1054 | ||
1072 | spin_lock_irq(&file->async_file->lock); | 1055 | ib_uverbs_release_uevent(file, uobj); |
1073 | list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { | ||
1074 | list_del(&evt->list); | ||
1075 | kfree(evt); | ||
1076 | } | ||
1077 | spin_unlock_irq(&file->async_file->lock); | ||
1078 | 1056 | ||
1079 | resp.events_reported = uobj->events_reported; | 1057 | resp.events_reported = uobj->events_reported; |
1080 | 1058 | ||
@@ -1741,7 +1719,6 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, | |||
1741 | struct ib_uverbs_destroy_srq_resp resp; | 1719 | struct ib_uverbs_destroy_srq_resp resp; |
1742 | struct ib_srq *srq; | 1720 | struct ib_srq *srq; |
1743 | struct ib_uevent_object *uobj; | 1721 | struct ib_uevent_object *uobj; |
1744 | struct ib_uverbs_event *evt, *tmp; | ||
1745 | int ret = -EINVAL; | 1722 | int ret = -EINVAL; |
1746 | 1723 | ||
1747 | if (copy_from_user(&cmd, buf, sizeof cmd)) | 1724 | if (copy_from_user(&cmd, buf, sizeof cmd)) |
@@ -1767,12 +1744,7 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, | |||
1767 | list_del(&uobj->uobject.list); | 1744 | list_del(&uobj->uobject.list); |
1768 | up(&file->mutex); | 1745 | up(&file->mutex); |
1769 | 1746 | ||
1770 | spin_lock_irq(&file->async_file->lock); | 1747 | ib_uverbs_release_uevent(file, uobj); |
1771 | list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { | ||
1772 | list_del(&evt->list); | ||
1773 | kfree(evt); | ||
1774 | } | ||
1775 | spin_unlock_irq(&file->async_file->lock); | ||
1776 | 1748 | ||
1777 | resp.events_reported = uobj->events_reported; | 1749 | resp.events_reported = uobj->events_reported; |
1778 | 1750 | ||
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 251c752a7ae6..ac08d2c93ea1 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <linux/poll.h> | 44 | #include <linux/poll.h> |
45 | #include <linux/file.h> | 45 | #include <linux/file.h> |
46 | #include <linux/mount.h> | 46 | #include <linux/mount.h> |
47 | #include <linux/cdev.h> | ||
47 | 48 | ||
48 | #include <asm/uaccess.h> | 49 | #include <asm/uaccess.h> |
49 | 50 | ||
@@ -63,6 +64,8 @@ enum { | |||
63 | 64 | ||
64 | #define IB_UVERBS_BASE_DEV MKDEV(IB_UVERBS_MAJOR, IB_UVERBS_BASE_MINOR) | 65 | #define IB_UVERBS_BASE_DEV MKDEV(IB_UVERBS_MAJOR, IB_UVERBS_BASE_MINOR) |
65 | 66 | ||
67 | static struct class *uverbs_class; | ||
68 | |||
66 | DECLARE_MUTEX(ib_uverbs_idr_mutex); | 69 | DECLARE_MUTEX(ib_uverbs_idr_mutex); |
67 | DEFINE_IDR(ib_uverbs_pd_idr); | 70 | DEFINE_IDR(ib_uverbs_pd_idr); |
68 | DEFINE_IDR(ib_uverbs_mr_idr); | 71 | DEFINE_IDR(ib_uverbs_mr_idr); |
@@ -73,6 +76,7 @@ DEFINE_IDR(ib_uverbs_qp_idr); | |||
73 | DEFINE_IDR(ib_uverbs_srq_idr); | 76 | DEFINE_IDR(ib_uverbs_srq_idr); |
74 | 77 | ||
75 | static spinlock_t map_lock; | 78 | static spinlock_t map_lock; |
79 | static struct ib_uverbs_device *dev_table[IB_UVERBS_MAX_DEVICES]; | ||
76 | static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); | 80 | static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); |
77 | 81 | ||
78 | static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, | 82 | static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, |
@@ -110,7 +114,54 @@ static struct vfsmount *uverbs_event_mnt; | |||
110 | static void ib_uverbs_add_one(struct ib_device *device); | 114 | static void ib_uverbs_add_one(struct ib_device *device); |
111 | static void ib_uverbs_remove_one(struct ib_device *device); | 115 | static void ib_uverbs_remove_one(struct ib_device *device); |
112 | 116 | ||
113 | static int ib_dealloc_ucontext(struct ib_ucontext *context) | 117 | static void ib_uverbs_release_dev(struct kref *ref) |
118 | { | ||
119 | struct ib_uverbs_device *dev = | ||
120 | container_of(ref, struct ib_uverbs_device, ref); | ||
121 | |||
122 | kfree(dev); | ||
123 | } | ||
124 | |||
125 | void ib_uverbs_release_ucq(struct ib_uverbs_file *file, | ||
126 | struct ib_uverbs_event_file *ev_file, | ||
127 | struct ib_ucq_object *uobj) | ||
128 | { | ||
129 | struct ib_uverbs_event *evt, *tmp; | ||
130 | |||
131 | if (ev_file) { | ||
132 | spin_lock_irq(&ev_file->lock); | ||
133 | list_for_each_entry_safe(evt, tmp, &uobj->comp_list, obj_list) { | ||
134 | list_del(&evt->list); | ||
135 | kfree(evt); | ||
136 | } | ||
137 | spin_unlock_irq(&ev_file->lock); | ||
138 | |||
139 | kref_put(&ev_file->ref, ib_uverbs_release_event_file); | ||
140 | } | ||
141 | |||
142 | spin_lock_irq(&file->async_file->lock); | ||
143 | list_for_each_entry_safe(evt, tmp, &uobj->async_list, obj_list) { | ||
144 | list_del(&evt->list); | ||
145 | kfree(evt); | ||
146 | } | ||
147 | spin_unlock_irq(&file->async_file->lock); | ||
148 | } | ||
149 | |||
150 | void ib_uverbs_release_uevent(struct ib_uverbs_file *file, | ||
151 | struct ib_uevent_object *uobj) | ||
152 | { | ||
153 | struct ib_uverbs_event *evt, *tmp; | ||
154 | |||
155 | spin_lock_irq(&file->async_file->lock); | ||
156 | list_for_each_entry_safe(evt, tmp, &uobj->event_list, obj_list) { | ||
157 | list_del(&evt->list); | ||
158 | kfree(evt); | ||
159 | } | ||
160 | spin_unlock_irq(&file->async_file->lock); | ||
161 | } | ||
162 | |||
163 | static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, | ||
164 | struct ib_ucontext *context) | ||
114 | { | 165 | { |
115 | struct ib_uobject *uobj, *tmp; | 166 | struct ib_uobject *uobj, *tmp; |
116 | 167 | ||
@@ -129,26 +180,36 @@ static int ib_dealloc_ucontext(struct ib_ucontext *context) | |||
129 | 180 | ||
130 | list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { | 181 | list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) { |
131 | struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id); | 182 | struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id); |
183 | struct ib_uevent_object *uevent = | ||
184 | container_of(uobj, struct ib_uevent_object, uobject); | ||
132 | idr_remove(&ib_uverbs_qp_idr, uobj->id); | 185 | idr_remove(&ib_uverbs_qp_idr, uobj->id); |
133 | ib_destroy_qp(qp); | 186 | ib_destroy_qp(qp); |
134 | list_del(&uobj->list); | 187 | list_del(&uobj->list); |
135 | kfree(container_of(uobj, struct ib_uevent_object, uobject)); | 188 | ib_uverbs_release_uevent(file, uevent); |
189 | kfree(uevent); | ||
136 | } | 190 | } |
137 | 191 | ||
138 | list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) { | 192 | list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) { |
139 | struct ib_cq *cq = idr_find(&ib_uverbs_cq_idr, uobj->id); | 193 | struct ib_cq *cq = idr_find(&ib_uverbs_cq_idr, uobj->id); |
194 | struct ib_uverbs_event_file *ev_file = cq->cq_context; | ||
195 | struct ib_ucq_object *ucq = | ||
196 | container_of(uobj, struct ib_ucq_object, uobject); | ||
140 | idr_remove(&ib_uverbs_cq_idr, uobj->id); | 197 | idr_remove(&ib_uverbs_cq_idr, uobj->id); |
141 | ib_destroy_cq(cq); | 198 | ib_destroy_cq(cq); |
142 | list_del(&uobj->list); | 199 | list_del(&uobj->list); |
143 | kfree(container_of(uobj, struct ib_ucq_object, uobject)); | 200 | ib_uverbs_release_ucq(file, ev_file, ucq); |
201 | kfree(ucq); | ||
144 | } | 202 | } |
145 | 203 | ||
146 | list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) { | 204 | list_for_each_entry_safe(uobj, tmp, &context->srq_list, list) { |
147 | struct ib_srq *srq = idr_find(&ib_uverbs_srq_idr, uobj->id); | 205 | struct ib_srq *srq = idr_find(&ib_uverbs_srq_idr, uobj->id); |
206 | struct ib_uevent_object *uevent = | ||
207 | container_of(uobj, struct ib_uevent_object, uobject); | ||
148 | idr_remove(&ib_uverbs_srq_idr, uobj->id); | 208 | idr_remove(&ib_uverbs_srq_idr, uobj->id); |
149 | ib_destroy_srq(srq); | 209 | ib_destroy_srq(srq); |
150 | list_del(&uobj->list); | 210 | list_del(&uobj->list); |
151 | kfree(container_of(uobj, struct ib_uevent_object, uobject)); | 211 | ib_uverbs_release_uevent(file, uevent); |
212 | kfree(uevent); | ||
152 | } | 213 | } |
153 | 214 | ||
154 | /* XXX Free MWs */ | 215 | /* XXX Free MWs */ |
@@ -187,6 +248,8 @@ static void ib_uverbs_release_file(struct kref *ref) | |||
187 | container_of(ref, struct ib_uverbs_file, ref); | 248 | container_of(ref, struct ib_uverbs_file, ref); |
188 | 249 | ||
189 | module_put(file->device->ib_dev->owner); | 250 | module_put(file->device->ib_dev->owner); |
251 | kref_put(&file->device->ref, ib_uverbs_release_dev); | ||
252 | |||
190 | kfree(file); | 253 | kfree(file); |
191 | } | 254 | } |
192 | 255 | ||
@@ -552,36 +615,58 @@ static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma) | |||
552 | 615 | ||
553 | static int ib_uverbs_open(struct inode *inode, struct file *filp) | 616 | static int ib_uverbs_open(struct inode *inode, struct file *filp) |
554 | { | 617 | { |
555 | struct ib_uverbs_device *dev = | 618 | struct ib_uverbs_device *dev; |
556 | container_of(inode->i_cdev, struct ib_uverbs_device, dev); | ||
557 | struct ib_uverbs_file *file; | 619 | struct ib_uverbs_file *file; |
620 | int ret; | ||
558 | 621 | ||
559 | if (!try_module_get(dev->ib_dev->owner)) | 622 | spin_lock(&map_lock); |
560 | return -ENODEV; | 623 | dev = dev_table[iminor(inode) - IB_UVERBS_BASE_MINOR]; |
624 | if (dev) | ||
625 | kref_get(&dev->ref); | ||
626 | spin_unlock(&map_lock); | ||
627 | |||
628 | if (!dev) | ||
629 | return -ENXIO; | ||
630 | |||
631 | if (!try_module_get(dev->ib_dev->owner)) { | ||
632 | ret = -ENODEV; | ||
633 | goto err; | ||
634 | } | ||
561 | 635 | ||
562 | file = kmalloc(sizeof *file, GFP_KERNEL); | 636 | file = kmalloc(sizeof *file, GFP_KERNEL); |
563 | if (!file) { | 637 | if (!file) { |
564 | module_put(dev->ib_dev->owner); | 638 | ret = -ENOMEM; |
565 | return -ENOMEM; | 639 | goto err_module; |
566 | } | 640 | } |
567 | 641 | ||
568 | file->device = dev; | 642 | file->device = dev; |
569 | file->ucontext = NULL; | 643 | file->ucontext = NULL; |
644 | file->async_file = NULL; | ||
570 | kref_init(&file->ref); | 645 | kref_init(&file->ref); |
571 | init_MUTEX(&file->mutex); | 646 | init_MUTEX(&file->mutex); |
572 | 647 | ||
573 | filp->private_data = file; | 648 | filp->private_data = file; |
574 | 649 | ||
575 | return 0; | 650 | return 0; |
651 | |||
652 | err_module: | ||
653 | module_put(dev->ib_dev->owner); | ||
654 | |||
655 | err: | ||
656 | kref_put(&dev->ref, ib_uverbs_release_dev); | ||
657 | |||
658 | return ret; | ||
576 | } | 659 | } |
577 | 660 | ||
578 | static int ib_uverbs_close(struct inode *inode, struct file *filp) | 661 | static int ib_uverbs_close(struct inode *inode, struct file *filp) |
579 | { | 662 | { |
580 | struct ib_uverbs_file *file = filp->private_data; | 663 | struct ib_uverbs_file *file = filp->private_data; |
581 | 664 | ||
582 | ib_dealloc_ucontext(file->ucontext); | 665 | ib_uverbs_cleanup_ucontext(file, file->ucontext); |
666 | |||
667 | if (file->async_file) | ||
668 | kref_put(&file->async_file->ref, ib_uverbs_release_event_file); | ||
583 | 669 | ||
584 | kref_put(&file->async_file->ref, ib_uverbs_release_event_file); | ||
585 | kref_put(&file->ref, ib_uverbs_release_file); | 670 | kref_put(&file->ref, ib_uverbs_release_file); |
586 | 671 | ||
587 | return 0; | 672 | return 0; |
@@ -610,8 +695,10 @@ static struct ib_client uverbs_client = { | |||
610 | 695 | ||
611 | static ssize_t show_ibdev(struct class_device *class_dev, char *buf) | 696 | static ssize_t show_ibdev(struct class_device *class_dev, char *buf) |
612 | { | 697 | { |
613 | struct ib_uverbs_device *dev = | 698 | struct ib_uverbs_device *dev = class_get_devdata(class_dev); |
614 | container_of(class_dev, struct ib_uverbs_device, class_dev); | 699 | |
700 | if (!dev) | ||
701 | return -ENODEV; | ||
615 | 702 | ||
616 | return sprintf(buf, "%s\n", dev->ib_dev->name); | 703 | return sprintf(buf, "%s\n", dev->ib_dev->name); |
617 | } | 704 | } |
@@ -619,28 +706,15 @@ static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); | |||
619 | 706 | ||
620 | static ssize_t show_dev_abi_version(struct class_device *class_dev, char *buf) | 707 | static ssize_t show_dev_abi_version(struct class_device *class_dev, char *buf) |
621 | { | 708 | { |
622 | struct ib_uverbs_device *dev = | 709 | struct ib_uverbs_device *dev = class_get_devdata(class_dev); |
623 | container_of(class_dev, struct ib_uverbs_device, class_dev); | 710 | |
711 | if (!dev) | ||
712 | return -ENODEV; | ||
624 | 713 | ||
625 | return sprintf(buf, "%d\n", dev->ib_dev->uverbs_abi_ver); | 714 | return sprintf(buf, "%d\n", dev->ib_dev->uverbs_abi_ver); |
626 | } | 715 | } |
627 | static CLASS_DEVICE_ATTR(abi_version, S_IRUGO, show_dev_abi_version, NULL); | 716 | static CLASS_DEVICE_ATTR(abi_version, S_IRUGO, show_dev_abi_version, NULL); |
628 | 717 | ||
629 | static void ib_uverbs_release_class_dev(struct class_device *class_dev) | ||
630 | { | ||
631 | struct ib_uverbs_device *dev = | ||
632 | container_of(class_dev, struct ib_uverbs_device, class_dev); | ||
633 | |||
634 | cdev_del(&dev->dev); | ||
635 | clear_bit(dev->devnum, dev_map); | ||
636 | kfree(dev); | ||
637 | } | ||
638 | |||
639 | static struct class uverbs_class = { | ||
640 | .name = "infiniband_verbs", | ||
641 | .release = ib_uverbs_release_class_dev | ||
642 | }; | ||
643 | |||
644 | static ssize_t show_abi_version(struct class *class, char *buf) | 718 | static ssize_t show_abi_version(struct class *class, char *buf) |
645 | { | 719 | { |
646 | return sprintf(buf, "%d\n", IB_USER_VERBS_ABI_VERSION); | 720 | return sprintf(buf, "%d\n", IB_USER_VERBS_ABI_VERSION); |
@@ -660,6 +734,8 @@ static void ib_uverbs_add_one(struct ib_device *device) | |||
660 | 734 | ||
661 | memset(uverbs_dev, 0, sizeof *uverbs_dev); | 735 | memset(uverbs_dev, 0, sizeof *uverbs_dev); |
662 | 736 | ||
737 | kref_init(&uverbs_dev->ref); | ||
738 | |||
663 | spin_lock(&map_lock); | 739 | spin_lock(&map_lock); |
664 | uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); | 740 | uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); |
665 | if (uverbs_dev->devnum >= IB_UVERBS_MAX_DEVICES) { | 741 | if (uverbs_dev->devnum >= IB_UVERBS_MAX_DEVICES) { |
@@ -672,40 +748,45 @@ static void ib_uverbs_add_one(struct ib_device *device) | |||
672 | uverbs_dev->ib_dev = device; | 748 | uverbs_dev->ib_dev = device; |
673 | uverbs_dev->num_comp_vectors = 1; | 749 | uverbs_dev->num_comp_vectors = 1; |
674 | 750 | ||
675 | if (device->mmap) | 751 | uverbs_dev->dev = cdev_alloc(); |
676 | cdev_init(&uverbs_dev->dev, &uverbs_mmap_fops); | 752 | if (!uverbs_dev->dev) |
677 | else | ||
678 | cdev_init(&uverbs_dev->dev, &uverbs_fops); | ||
679 | uverbs_dev->dev.owner = THIS_MODULE; | ||
680 | kobject_set_name(&uverbs_dev->dev.kobj, "uverbs%d", uverbs_dev->devnum); | ||
681 | if (cdev_add(&uverbs_dev->dev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1)) | ||
682 | goto err; | 753 | goto err; |
754 | uverbs_dev->dev->owner = THIS_MODULE; | ||
755 | uverbs_dev->dev->ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops; | ||
756 | kobject_set_name(&uverbs_dev->dev->kobj, "uverbs%d", uverbs_dev->devnum); | ||
757 | if (cdev_add(uverbs_dev->dev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1)) | ||
758 | goto err_cdev; | ||
683 | 759 | ||
684 | uverbs_dev->class_dev.class = &uverbs_class; | 760 | uverbs_dev->class_dev = class_device_create(uverbs_class, uverbs_dev->dev->dev, |
685 | uverbs_dev->class_dev.dev = device->dma_device; | 761 | device->dma_device, |
686 | uverbs_dev->class_dev.devt = uverbs_dev->dev.dev; | 762 | "uverbs%d", uverbs_dev->devnum); |
687 | snprintf(uverbs_dev->class_dev.class_id, BUS_ID_SIZE, "uverbs%d", uverbs_dev->devnum); | 763 | if (IS_ERR(uverbs_dev->class_dev)) |
688 | if (class_device_register(&uverbs_dev->class_dev)) | ||
689 | goto err_cdev; | 764 | goto err_cdev; |
690 | 765 | ||
691 | if (class_device_create_file(&uverbs_dev->class_dev, &class_device_attr_ibdev)) | 766 | class_set_devdata(uverbs_dev->class_dev, uverbs_dev); |
767 | |||
768 | if (class_device_create_file(uverbs_dev->class_dev, &class_device_attr_ibdev)) | ||
692 | goto err_class; | 769 | goto err_class; |
693 | if (class_device_create_file(&uverbs_dev->class_dev, &class_device_attr_abi_version)) | 770 | if (class_device_create_file(uverbs_dev->class_dev, &class_device_attr_abi_version)) |
694 | goto err_class; | 771 | goto err_class; |
695 | 772 | ||
773 | spin_lock(&map_lock); | ||
774 | dev_table[uverbs_dev->devnum] = uverbs_dev; | ||
775 | spin_unlock(&map_lock); | ||
776 | |||
696 | ib_set_client_data(device, &uverbs_client, uverbs_dev); | 777 | ib_set_client_data(device, &uverbs_client, uverbs_dev); |
697 | 778 | ||
698 | return; | 779 | return; |
699 | 780 | ||
700 | err_class: | 781 | err_class: |
701 | class_device_unregister(&uverbs_dev->class_dev); | 782 | class_device_destroy(uverbs_class, uverbs_dev->dev->dev); |
702 | 783 | ||
703 | err_cdev: | 784 | err_cdev: |
704 | cdev_del(&uverbs_dev->dev); | 785 | cdev_del(uverbs_dev->dev); |
705 | clear_bit(uverbs_dev->devnum, dev_map); | 786 | clear_bit(uverbs_dev->devnum, dev_map); |
706 | 787 | ||
707 | err: | 788 | err: |
708 | kfree(uverbs_dev); | 789 | kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); |
709 | return; | 790 | return; |
710 | } | 791 | } |
711 | 792 | ||
@@ -716,7 +797,16 @@ static void ib_uverbs_remove_one(struct ib_device *device) | |||
716 | if (!uverbs_dev) | 797 | if (!uverbs_dev) |
717 | return; | 798 | return; |
718 | 799 | ||
719 | class_device_unregister(&uverbs_dev->class_dev); | 800 | class_set_devdata(uverbs_dev->class_dev, NULL); |
801 | class_device_destroy(uverbs_class, uverbs_dev->dev->dev); | ||
802 | cdev_del(uverbs_dev->dev); | ||
803 | |||
804 | spin_lock(&map_lock); | ||
805 | dev_table[uverbs_dev->devnum] = NULL; | ||
806 | spin_unlock(&map_lock); | ||
807 | |||
808 | clear_bit(uverbs_dev->devnum, dev_map); | ||
809 | kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); | ||
720 | } | 810 | } |
721 | 811 | ||
722 | static struct super_block *uverbs_event_get_sb(struct file_system_type *fs_type, int flags, | 812 | static struct super_block *uverbs_event_get_sb(struct file_system_type *fs_type, int flags, |
@@ -746,13 +836,14 @@ static int __init ib_uverbs_init(void) | |||
746 | goto out; | 836 | goto out; |
747 | } | 837 | } |
748 | 838 | ||
749 | ret = class_register(&uverbs_class); | 839 | uverbs_class = class_create(THIS_MODULE, "infiniband_verbs"); |
750 | if (ret) { | 840 | if (IS_ERR(uverbs_class)) { |
841 | ret = PTR_ERR(uverbs_class); | ||
751 | printk(KERN_ERR "user_verbs: couldn't create class infiniband_verbs\n"); | 842 | printk(KERN_ERR "user_verbs: couldn't create class infiniband_verbs\n"); |
752 | goto out_chrdev; | 843 | goto out_chrdev; |
753 | } | 844 | } |
754 | 845 | ||
755 | ret = class_create_file(&uverbs_class, &class_attr_abi_version); | 846 | ret = class_create_file(uverbs_class, &class_attr_abi_version); |
756 | if (ret) { | 847 | if (ret) { |
757 | printk(KERN_ERR "user_verbs: couldn't create abi_version attribute\n"); | 848 | printk(KERN_ERR "user_verbs: couldn't create abi_version attribute\n"); |
758 | goto out_class; | 849 | goto out_class; |
@@ -786,7 +877,7 @@ out_fs: | |||
786 | unregister_filesystem(&uverbs_event_fs); | 877 | unregister_filesystem(&uverbs_event_fs); |
787 | 878 | ||
788 | out_class: | 879 | out_class: |
789 | class_unregister(&uverbs_class); | 880 | class_destroy(uverbs_class); |
790 | 881 | ||
791 | out_chrdev: | 882 | out_chrdev: |
792 | unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); | 883 | unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); |
@@ -800,7 +891,7 @@ static void __exit ib_uverbs_cleanup(void) | |||
800 | ib_unregister_client(&uverbs_client); | 891 | ib_unregister_client(&uverbs_client); |
801 | mntput(uverbs_event_mnt); | 892 | mntput(uverbs_event_mnt); |
802 | unregister_filesystem(&uverbs_event_fs); | 893 | unregister_filesystem(&uverbs_event_fs); |
803 | class_unregister(&uverbs_class); | 894 | class_destroy(uverbs_class); |
804 | unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); | 895 | unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES); |
805 | idr_destroy(&ib_uverbs_pd_idr); | 896 | idr_destroy(&ib_uverbs_pd_idr); |
806 | idr_destroy(&ib_uverbs_mr_idr); | 897 | idr_destroy(&ib_uverbs_mr_idr); |