diff options
author | Volodymyr Babchuk <vlad.babchuk@gmail.com> | 2017-11-29 07:48:37 -0500 |
---|---|---|
committer | Jens Wiklander <jens.wiklander@linaro.org> | 2017-12-15 07:36:18 -0500 |
commit | 217e0250cccb9e54d457991446cd3fab413085e1 (patch) | |
tree | 42906632546d8fe35890ac41a019f641fc1055a2 | |
parent | f58e236c9d665ad0af99c908de4a9b6f07e74dda (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.c | 40 | ||||
-rw-r--r-- | drivers/tee/tee_private.h | 3 | ||||
-rw-r--r-- | drivers/tee/tee_shm.c | 7 | ||||
-rw-r--r-- | include/linux/tee_drv.h | 7 |
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 | ||
71 | static int tee_release(struct inode *inode, struct file *filp) | 72 | void 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 | ||
80 | static 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 | |||
89 | void 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 | |||
97 | static void teedev_close_context(struct tee_context *ctx) | ||
98 | { | ||
99 | tee_device_put(ctx->teedev); | ||
100 | teedev_ctx_put(ctx); | ||
101 | } | ||
102 | |||
103 | static 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); | |||
73 | bool tee_device_get(struct tee_device *teedev); | 73 | bool tee_device_get(struct tee_device *teedev); |
74 | void tee_device_put(struct tee_device *teedev); | 74 | void tee_device_put(struct tee_device *teedev); |
75 | 75 | ||
76 | void teedev_ctx_get(struct tee_context *ctx); | ||
77 | void 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 | */ |
46 | struct tee_context { | 51 | struct 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 | ||
52 | struct tee_param_memref { | 59 | struct tee_param_memref { |