aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rpmsg
diff options
context:
space:
mode:
authorOhad Ben-Cohen <ohad@wizery.com>2012-06-07 08:39:35 -0400
committerOhad Ben-Cohen <ohad@wizery.com>2012-07-04 04:51:59 -0400
commit15fd943af50dbc5f7f4de33835795c72595f7bf4 (patch)
treeb35e37da3edf0b0166f14cf1d71e665d506b7fdf /drivers/rpmsg
parent5a081caa0414b9bbb82c17ffab9d6fe66edbb72f (diff)
rpmsg: make sure inflight messages don't invoke just-removed callbacks
When inbound messages arrive, rpmsg core looks up their associated endpoint (by destination address) and then invokes their callback. We've made sure that endpoints will never be de-allocated after they were found by rpmsg core, but we also need to protect against the (rare) scenario where the rpmsg driver was just removed, and its callback function isn't available anymore. This is achieved by introducing a callback mutex, which must be taken before the callback is invoked, and, obviously, before it is removed. Cc: stable <stable@vger.kernel.org> Reported-by: Fernando Guzman Lugo <fernando.lugo@ti.com> Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Diffstat (limited to 'drivers/rpmsg')
-rw-r--r--drivers/rpmsg/virtio_rpmsg_bus.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 9623327ba509..39d3aa41adda 100644
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
@@ -227,6 +227,7 @@ static struct rpmsg_endpoint *__rpmsg_create_ept(struct virtproc_info *vrp,
227 } 227 }
228 228
229 kref_init(&ept->refcount); 229 kref_init(&ept->refcount);
230 mutex_init(&ept->cb_lock);
230 231
231 ept->rpdev = rpdev; 232 ept->rpdev = rpdev;
232 ept->cb = cb; 233 ept->cb = cb;
@@ -324,10 +325,16 @@ EXPORT_SYMBOL(rpmsg_create_ept);
324static void 325static void
325__rpmsg_destroy_ept(struct virtproc_info *vrp, struct rpmsg_endpoint *ept) 326__rpmsg_destroy_ept(struct virtproc_info *vrp, struct rpmsg_endpoint *ept)
326{ 327{
328 /* make sure new inbound messages can't find this ept anymore */
327 mutex_lock(&vrp->endpoints_lock); 329 mutex_lock(&vrp->endpoints_lock);
328 idr_remove(&vrp->endpoints, ept->addr); 330 idr_remove(&vrp->endpoints, ept->addr);
329 mutex_unlock(&vrp->endpoints_lock); 331 mutex_unlock(&vrp->endpoints_lock);
330 332
333 /* make sure in-flight inbound messages won't invoke cb anymore */
334 mutex_lock(&ept->cb_lock);
335 ept->cb = NULL;
336 mutex_unlock(&ept->cb_lock);
337
331 kref_put(&ept->refcount, __ept_release); 338 kref_put(&ept->refcount, __ept_release);
332} 339}
333 340
@@ -821,14 +828,20 @@ static void rpmsg_recv_done(struct virtqueue *rvq)
821 828
822 mutex_unlock(&vrp->endpoints_lock); 829 mutex_unlock(&vrp->endpoints_lock);
823 830
824 if (ept && ept->cb) 831 if (ept) {
825 ept->cb(ept->rpdev, msg->data, msg->len, ept->priv, msg->src); 832 /* make sure ept->cb doesn't go away while we use it */
826 else 833 mutex_lock(&ept->cb_lock);
827 dev_warn(dev, "msg received with no recepient\n");
828 834
829 /* farewell, ept, we don't need you anymore */ 835 if (ept->cb)
830 if (ept) 836 ept->cb(ept->rpdev, msg->data, msg->len, ept->priv,
837 msg->src);
838
839 mutex_unlock(&ept->cb_lock);
840
841 /* farewell, ept, we don't need you anymore */
831 kref_put(&ept->refcount, __ept_release); 842 kref_put(&ept->refcount, __ept_release);
843 } else
844 dev_warn(dev, "msg received with no recepient\n");
832 845
833 /* publish the real size of the buffer */ 846 /* publish the real size of the buffer */
834 sg_init_one(&sg, msg, RPMSG_BUF_SIZE); 847 sg_init_one(&sg, msg, RPMSG_BUF_SIZE);