aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVolodymyr Babchuk <vlad.babchuk@gmail.com>2017-11-29 07:48:37 -0500
committerJens Wiklander <jens.wiklander@linaro.org>2017-12-15 07:36:18 -0500
commit217e0250cccb9e54d457991446cd3fab413085e1 (patch)
tree42906632546d8fe35890ac41a019f641fc1055a2
parentf58e236c9d665ad0af99c908de4a9b6f07e74dda (diff)
tee: use reference counting for tee_context
We need to ensure that tee_context is present until last shared buffer will be freed. Signed-off-by: Volodymyr Babchuk <vlad.babchuk@gmail.com> Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
-rw-r--r--drivers/tee/tee_core.c40
-rw-r--r--drivers/tee/tee_private.h3
-rw-r--r--drivers/tee/tee_shm.c7
-rw-r--r--include/linux/tee_drv.h7
4 files changed, 48 insertions, 9 deletions
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index 295910f5cdd0..3d49ac2e3c84 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -54,6 +54,7 @@ static int tee_open(struct inode *inode, struct file *filp)
54 goto err; 54 goto err;
55 } 55 }
56 56
57 kref_init(&ctx->refcount);
57 ctx->teedev = teedev; 58 ctx->teedev = teedev;
58 INIT_LIST_HEAD(&ctx->list_shm); 59 INIT_LIST_HEAD(&ctx->list_shm);
59 filp->private_data = ctx; 60 filp->private_data = ctx;
@@ -68,19 +69,40 @@ err:
68 return rc; 69 return rc;
69} 70}
70 71
71static int tee_release(struct inode *inode, struct file *filp) 72void teedev_ctx_get(struct tee_context *ctx)
72{ 73{
73 struct tee_context *ctx = filp->private_data; 74 if (ctx->releasing)
74 struct tee_device *teedev = ctx->teedev; 75 return;
75 struct tee_shm *shm; 76
77 kref_get(&ctx->refcount);
78}
76 79
80static void teedev_ctx_release(struct kref *ref)
81{
82 struct tee_context *ctx = container_of(ref, struct tee_context,
83 refcount);
84 ctx->releasing = true;
77 ctx->teedev->desc->ops->release(ctx); 85 ctx->teedev->desc->ops->release(ctx);
78 mutex_lock(&ctx->teedev->mutex);
79 list_for_each_entry(shm, &ctx->list_shm, link)
80 shm->ctx = NULL;
81 mutex_unlock(&ctx->teedev->mutex);
82 kfree(ctx); 86 kfree(ctx);
83 tee_device_put(teedev); 87}
88
89void teedev_ctx_put(struct tee_context *ctx)
90{
91 if (ctx->releasing)
92 return;
93
94 kref_put(&ctx->refcount, teedev_ctx_release);
95}
96
97static void teedev_close_context(struct tee_context *ctx)
98{
99 tee_device_put(ctx->teedev);
100 teedev_ctx_put(ctx);
101}
102
103static int tee_release(struct inode *inode, struct file *filp)
104{
105 teedev_close_context(filp->private_data);
84 return 0; 106 return 0;
85} 107}
86 108
diff --git a/drivers/tee/tee_private.h b/drivers/tee/tee_private.h
index 2bc2b5ab1661..85d99d621603 100644
--- a/drivers/tee/tee_private.h
+++ b/drivers/tee/tee_private.h
@@ -73,4 +73,7 @@ int tee_shm_get_fd(struct tee_shm *shm);
73bool tee_device_get(struct tee_device *teedev); 73bool tee_device_get(struct tee_device *teedev);
74void tee_device_put(struct tee_device *teedev); 74void tee_device_put(struct tee_device *teedev);
75 75
76void teedev_ctx_get(struct tee_context *ctx);
77void teedev_ctx_put(struct tee_context *ctx);
78
76#endif /*TEE_PRIVATE_H*/ 79#endif /*TEE_PRIVATE_H*/
diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c
index 11d11a46d86e..ba02a15eefcb 100644
--- a/drivers/tee/tee_shm.c
+++ b/drivers/tee/tee_shm.c
@@ -53,6 +53,9 @@ static void tee_shm_release(struct tee_shm *shm)
53 kfree(shm->pages); 53 kfree(shm->pages);
54 } 54 }
55 55
56 if (shm->ctx)
57 teedev_ctx_put(shm->ctx);
58
56 kfree(shm); 59 kfree(shm);
57 60
58 tee_device_put(teedev); 61 tee_device_put(teedev);
@@ -187,6 +190,7 @@ struct tee_shm *__tee_shm_alloc(struct tee_context *ctx,
187 } 190 }
188 191
189 if (ctx) { 192 if (ctx) {
193 teedev_ctx_get(ctx);
190 mutex_lock(&teedev->mutex); 194 mutex_lock(&teedev->mutex);
191 list_add_tail(&shm->link, &ctx->list_shm); 195 list_add_tail(&shm->link, &ctx->list_shm);
192 mutex_unlock(&teedev->mutex); 196 mutex_unlock(&teedev->mutex);
@@ -253,6 +257,8 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
253 return ERR_PTR(-ENOTSUPP); 257 return ERR_PTR(-ENOTSUPP);
254 } 258 }
255 259
260 teedev_ctx_get(ctx);
261
256 shm = kzalloc(sizeof(*shm), GFP_KERNEL); 262 shm = kzalloc(sizeof(*shm), GFP_KERNEL);
257 if (!shm) { 263 if (!shm) {
258 ret = ERR_PTR(-ENOMEM); 264 ret = ERR_PTR(-ENOMEM);
@@ -334,6 +340,7 @@ err:
334 kfree(shm->pages); 340 kfree(shm->pages);
335 } 341 }
336 kfree(shm); 342 kfree(shm);
343 teedev_ctx_put(ctx);
337 tee_device_put(teedev); 344 tee_device_put(teedev);
338 return ret; 345 return ret;
339} 346}
diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h
index 0f86a480c204..157e8d06bf49 100644
--- a/include/linux/tee_drv.h
+++ b/include/linux/tee_drv.h
@@ -17,6 +17,7 @@
17 17
18#include <linux/types.h> 18#include <linux/types.h>
19#include <linux/idr.h> 19#include <linux/idr.h>
20#include <linux/kref.h>
20#include <linux/list.h> 21#include <linux/list.h>
21#include <linux/tee.h> 22#include <linux/tee.h>
22 23
@@ -42,11 +43,17 @@ struct tee_shm_pool;
42 * @teedev: pointer to this drivers struct tee_device 43 * @teedev: pointer to this drivers struct tee_device
43 * @list_shm: List of shared memory object owned by this context 44 * @list_shm: List of shared memory object owned by this context
44 * @data: driver specific context data, managed by the driver 45 * @data: driver specific context data, managed by the driver
46 * @refcount: reference counter for this structure
47 * @releasing: flag that indicates if context is being released right now.
48 * It is needed to break circular dependency on context during
49 * shared memory release.
45 */ 50 */
46struct tee_context { 51struct tee_context {
47 struct tee_device *teedev; 52 struct tee_device *teedev;
48 struct list_head list_shm; 53 struct list_head list_shm;
49 void *data; 54 void *data;
55 struct kref refcount;
56 bool releasing;
50}; 57};
51 58
52struct tee_param_memref { 59struct tee_param_memref {