[1/5] misc: fastrpc: Reference count channel context

Message ID 20190823100622.3892-2-srinivas.kandagatla@linaro.org
State Superseded
Headers show
Series
  • misc: fastrpc: few fixes
Related show

Commit Message

Srinivas Kandagatla Aug. 23, 2019, 10:06 a.m.
From: Bjorn Andersson <bjorn.andersson@linaro.org>


The channel context is referenced from the fastrpc user and might as
user space holds the file descriptor open outlive the fastrpc device,
which is removed when the remote processor is shutting down.

Reference count the channel context in order to retain this object until
all references has been relinquished.

TEST=stop and start remote proc1 using sysfs

Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>

Signed-off-by: Mayank Chopra <mak.chopra@codeaurora.org>

Signed-off-by: Abhinav Asati <asatiabhi@codeaurora.org>

Signed-off-by: Vamsi Singamsetty <vamssi@codeaurora.org>

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

---
 drivers/misc/fastrpc.c | 43 +++++++++++++++++++++++++++++++++++++-----
 1 file changed, 38 insertions(+), 5 deletions(-)

-- 
2.21.0

Comments

Greg KH Aug. 28, 2019, 8:53 p.m. | #1
On Fri, Aug 23, 2019 at 11:06:18AM +0100, Srinivas Kandagatla wrote:
> From: Bjorn Andersson <bjorn.andersson@linaro.org>

> 

> The channel context is referenced from the fastrpc user and might as

> user space holds the file descriptor open outlive the fastrpc device,

> which is removed when the remote processor is shutting down.

> 

> Reference count the channel context in order to retain this object until

> all references has been relinquished.

> 

> TEST=stop and start remote proc1 using sysfs


What is this for?

Please fix up the series and resend so that I do not have to hand-edit
the changelog text.

thanks,

greg k-h

Patch

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index c790585da14c..c019e867e7fa 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -186,6 +186,7 @@  struct fastrpc_channel_ctx {
 	struct idr ctx_idr;
 	struct list_head users;
 	struct miscdevice miscdev;
+	struct kref refcount;
 };
 
 struct fastrpc_user {
@@ -293,6 +294,25 @@  static int fastrpc_buf_alloc(struct fastrpc_user *fl, struct device *dev,
 	return 0;
 }
 
+static void fastrpc_channel_ctx_free(struct kref *ref)
+{
+	struct fastrpc_channel_ctx *cctx;
+
+	cctx = container_of(ref, struct fastrpc_channel_ctx, refcount);
+
+	kfree(cctx);
+}
+
+static void fastrpc_channel_ctx_get(struct fastrpc_channel_ctx *cctx)
+{
+	kref_get(&cctx->refcount);
+}
+
+static void fastrpc_channel_ctx_put(struct fastrpc_channel_ctx *cctx)
+{
+	kref_put(&cctx->refcount, fastrpc_channel_ctx_free);
+}
+
 static void fastrpc_context_free(struct kref *ref)
 {
 	struct fastrpc_invoke_ctx *ctx;
@@ -316,6 +336,8 @@  static void fastrpc_context_free(struct kref *ref)
 	kfree(ctx->maps);
 	kfree(ctx->olaps);
 	kfree(ctx);
+
+	fastrpc_channel_ctx_put(cctx);
 }
 
 static void fastrpc_context_get(struct fastrpc_invoke_ctx *ctx)
@@ -422,6 +444,9 @@  static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
 		fastrpc_get_buff_overlaps(ctx);
 	}
 
+	/* Released in fastrpc_context_put() */
+	fastrpc_channel_ctx_get(cctx);
+
 	ctx->sc = sc;
 	ctx->retval = -1;
 	ctx->pid = current->pid;
@@ -451,6 +476,7 @@  static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
 	spin_lock(&user->lock);
 	list_del(&ctx->node);
 	spin_unlock(&user->lock);
+	fastrpc_channel_ctx_put(cctx);
 	kfree(ctx->maps);
 	kfree(ctx->olaps);
 	kfree(ctx);
@@ -1123,6 +1149,7 @@  static int fastrpc_device_release(struct inode *inode, struct file *file)
 	}
 
 	fastrpc_session_free(cctx, fl->sctx);
+	fastrpc_channel_ctx_put(cctx);
 
 	mutex_destroy(&fl->mutex);
 	kfree(fl);
@@ -1141,6 +1168,9 @@  static int fastrpc_device_open(struct inode *inode, struct file *filp)
 	if (!fl)
 		return -ENOMEM;
 
+	/* Released in fastrpc_device_release() */
+	fastrpc_channel_ctx_get(cctx);
+
 	filp->private_data = fl;
 	spin_lock_init(&fl->lock);
 	mutex_init(&fl->mutex);
@@ -1398,10 +1428,6 @@  static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
 	int i, err, domain_id = -1;
 	const char *domain;
 
-	data = devm_kzalloc(rdev, sizeof(*data), GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
 	err = of_property_read_string(rdev->of_node, "label", &domain);
 	if (err) {
 		dev_info(rdev, "FastRPC Domain not specified in DT\n");
@@ -1420,6 +1446,10 @@  static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
 		return -EINVAL;
 	}
 
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
 	data->miscdev.minor = MISC_DYNAMIC_MINOR;
 	data->miscdev.name = kasprintf(GFP_KERNEL, "fastrpc-%s",
 				domains[domain_id]);
@@ -1428,6 +1458,8 @@  static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
 	if (err)
 		return err;
 
+	kref_init(&data->refcount);
+
 	dev_set_drvdata(&rpdev->dev, data);
 	dma_set_mask_and_coherent(rdev, DMA_BIT_MASK(32));
 	INIT_LIST_HEAD(&data->users);
@@ -1462,7 +1494,8 @@  static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
 
 	misc_deregister(&cctx->miscdev);
 	of_platform_depopulate(&rpdev->dev);
-	kfree(cctx);
+
+	fastrpc_channel_ctx_put(cctx);
 }
 
 static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,