aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/rpmsg/virtio_rpmsg_bus.c25
-rw-r--r--include/linux/rpmsg.h3
2 files changed, 22 insertions, 6 deletions
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
index 9623327ba50..39d3aa41add 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);
diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h
index 195f373590b..82a673905ed 100644
--- a/include/linux/rpmsg.h
+++ b/include/linux/rpmsg.h
@@ -39,6 +39,7 @@
39#include <linux/device.h> 39#include <linux/device.h>
40#include <linux/mod_devicetable.h> 40#include <linux/mod_devicetable.h>
41#include <linux/kref.h> 41#include <linux/kref.h>
42#include <linux/mutex.h>
42 43
43/* The feature bitmap for virtio rpmsg */ 44/* The feature bitmap for virtio rpmsg */
44#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */ 45#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
@@ -123,6 +124,7 @@ typedef void (*rpmsg_rx_cb_t)(struct rpmsg_channel *, void *, int, void *, u32);
123 * @rpdev: rpmsg channel device 124 * @rpdev: rpmsg channel device
124 * @refcount: when this drops to zero, the ept is deallocated 125 * @refcount: when this drops to zero, the ept is deallocated
125 * @cb: rx callback handler 126 * @cb: rx callback handler
127 * @cb_lock: must be taken before accessing/changing @cb
126 * @addr: local rpmsg address 128 * @addr: local rpmsg address
127 * @priv: private data for the driver's use 129 * @priv: private data for the driver's use
128 * 130 *
@@ -144,6 +146,7 @@ struct rpmsg_endpoint {
144 struct rpmsg_channel *rpdev; 146 struct rpmsg_channel *rpdev;
145 struct kref refcount; 147 struct kref refcount;
146 rpmsg_rx_cb_t cb; 148 rpmsg_rx_cb_t cb;
149 struct mutex cb_lock;
147 u32 addr; 150 u32 addr;
148 void *priv; 151 void *priv;
149}; 152};