diff options
Diffstat (limited to 'drivers/rpmsg')
-rw-r--r-- | drivers/rpmsg/virtio_rpmsg_bus.c | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c index 75506ec2840e..9623327ba509 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c | |||
@@ -188,6 +188,26 @@ static int rpmsg_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
188 | rpdev->id.name); | 188 | rpdev->id.name); |
189 | } | 189 | } |
190 | 190 | ||
191 | /** | ||
192 | * __ept_release() - deallocate an rpmsg endpoint | ||
193 | * @kref: the ept's reference count | ||
194 | * | ||
195 | * This function deallocates an ept, and is invoked when its @kref refcount | ||
196 | * drops to zero. | ||
197 | * | ||
198 | * Never invoke this function directly! | ||
199 | */ | ||
200 | static void __ept_release(struct kref *kref) | ||
201 | { | ||
202 | struct rpmsg_endpoint *ept = container_of(kref, struct rpmsg_endpoint, | ||
203 | refcount); | ||
204 | /* | ||
205 | * At this point no one holds a reference to ept anymore, | ||
206 | * so we can directly free it | ||
207 | */ | ||
208 | kfree(ept); | ||
209 | } | ||
210 | |||
191 | /* for more info, see below documentation of rpmsg_create_ept() */ | 211 | /* for more info, see below documentation of rpmsg_create_ept() */ |
192 | static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp, | 212 | static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp, |
193 | struct rpmsg_channel *rpdev, rpmsg_rx_cb_t cb, | 213 | struct rpmsg_channel *rpdev, rpmsg_rx_cb_t cb, |
@@ -206,6 +226,8 @@ static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp, | |||
206 | return NULL; | 226 | return NULL; |
207 | } | 227 | } |
208 | 228 | ||
229 | kref_init(&ept->refcount); | ||
230 | |||
209 | ept->rpdev = rpdev; | 231 | ept->rpdev = rpdev; |
210 | ept->cb = cb; | 232 | ept->cb = cb; |
211 | ept->priv = priv; | 233 | ept->priv = priv; |
@@ -238,7 +260,7 @@ rem_idr: | |||
238 | idr_remove(&vrp->endpoints, request); | 260 | idr_remove(&vrp->endpoints, request); |
239 | free_ept: | 261 | free_ept: |
240 | mutex_unlock(&vrp->endpoints_lock); | 262 | mutex_unlock(&vrp->endpoints_lock); |
241 | kfree(ept); | 263 | kref_put(&ept->refcount, __ept_release); |
242 | return NULL; | 264 | return NULL; |
243 | } | 265 | } |
244 | 266 | ||
@@ -306,7 +328,7 @@ __rpmsg_destroy_ept(struct virtproc_info *vrp, struct rpmsg_endpoint *ept) | |||
306 | idr_remove(&vrp->endpoints, ept->addr); | 328 | idr_remove(&vrp->endpoints, ept->addr); |
307 | mutex_unlock(&vrp->endpoints_lock); | 329 | mutex_unlock(&vrp->endpoints_lock); |
308 | 330 | ||
309 | kfree(ept); | 331 | kref_put(&ept->refcount, __ept_release); |
310 | } | 332 | } |
311 | 333 | ||
312 | /** | 334 | /** |
@@ -790,7 +812,13 @@ static void rpmsg_recv_done(struct virtqueue *rvq) | |||
790 | 812 | ||
791 | /* use the dst addr to fetch the callback of the appropriate user */ | 813 | /* use the dst addr to fetch the callback of the appropriate user */ |
792 | mutex_lock(&vrp->endpoints_lock); | 814 | mutex_lock(&vrp->endpoints_lock); |
815 | |||
793 | ept = idr_find(&vrp->endpoints, msg->dst); | 816 | ept = idr_find(&vrp->endpoints, msg->dst); |
817 | |||
818 | /* let's make sure no one deallocates ept while we use it */ | ||
819 | if (ept) | ||
820 | kref_get(&ept->refcount); | ||
821 | |||
794 | mutex_unlock(&vrp->endpoints_lock); | 822 | mutex_unlock(&vrp->endpoints_lock); |
795 | 823 | ||
796 | if (ept && ept->cb) | 824 | if (ept && ept->cb) |
@@ -798,6 +826,10 @@ static void rpmsg_recv_done(struct virtqueue *rvq) | |||
798 | else | 826 | else |
799 | dev_warn(dev, "msg received with no recepient\n"); | 827 | dev_warn(dev, "msg received with no recepient\n"); |
800 | 828 | ||
829 | /* farewell, ept, we don't need you anymore */ | ||
830 | if (ept) | ||
831 | kref_put(&ept->refcount, __ept_release); | ||
832 | |||
801 | /* publish the real size of the buffer */ | 833 | /* publish the real size of the buffer */ |
802 | sg_init_one(&sg, msg, RPMSG_BUF_SIZE); | 834 | sg_init_one(&sg, msg, RPMSG_BUF_SIZE); |
803 | 835 | ||