aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rpmsg
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rpmsg')
-rw-r--r--drivers/rpmsg/virtio_rpmsg_bus.c36
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 */
200static 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() */
192static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp, 212static 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);
239free_ept: 261free_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