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>
This commit is contained in:
parent
f58e236c9d
commit
217e0250cc
4 changed files with 50 additions and 11 deletions
|
@ -54,6 +54,7 @@ static int tee_open(struct inode *inode, struct file *filp)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kref_init(&ctx->refcount);
|
||||||
ctx->teedev = teedev;
|
ctx->teedev = teedev;
|
||||||
INIT_LIST_HEAD(&ctx->list_shm);
|
INIT_LIST_HEAD(&ctx->list_shm);
|
||||||
filp->private_data = ctx;
|
filp->private_data = ctx;
|
||||||
|
@ -68,19 +69,40 @@ err:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void teedev_ctx_get(struct tee_context *ctx)
|
||||||
|
{
|
||||||
|
if (ctx->releasing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
kref_get(&ctx->refcount);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void teedev_ctx_release(struct kref *ref)
|
||||||
|
{
|
||||||
|
struct tee_context *ctx = container_of(ref, struct tee_context,
|
||||||
|
refcount);
|
||||||
|
ctx->releasing = true;
|
||||||
|
ctx->teedev->desc->ops->release(ctx);
|
||||||
|
kfree(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void teedev_ctx_put(struct tee_context *ctx)
|
||||||
|
{
|
||||||
|
if (ctx->releasing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
kref_put(&ctx->refcount, teedev_ctx_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void teedev_close_context(struct tee_context *ctx)
|
||||||
|
{
|
||||||
|
tee_device_put(ctx->teedev);
|
||||||
|
teedev_ctx_put(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
static int tee_release(struct inode *inode, struct file *filp)
|
static int tee_release(struct inode *inode, struct file *filp)
|
||||||
{
|
{
|
||||||
struct tee_context *ctx = filp->private_data;
|
teedev_close_context(filp->private_data);
|
||||||
struct tee_device *teedev = ctx->teedev;
|
|
||||||
struct tee_shm *shm;
|
|
||||||
|
|
||||||
ctx->teedev->desc->ops->release(ctx);
|
|
||||||
mutex_lock(&ctx->teedev->mutex);
|
|
||||||
list_for_each_entry(shm, &ctx->list_shm, link)
|
|
||||||
shm->ctx = NULL;
|
|
||||||
mutex_unlock(&ctx->teedev->mutex);
|
|
||||||
kfree(ctx);
|
|
||||||
tee_device_put(teedev);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,4 +73,7 @@ int tee_shm_get_fd(struct tee_shm *shm);
|
||||||
bool tee_device_get(struct tee_device *teedev);
|
bool tee_device_get(struct tee_device *teedev);
|
||||||
void tee_device_put(struct tee_device *teedev);
|
void tee_device_put(struct tee_device *teedev);
|
||||||
|
|
||||||
|
void teedev_ctx_get(struct tee_context *ctx);
|
||||||
|
void teedev_ctx_put(struct tee_context *ctx);
|
||||||
|
|
||||||
#endif /*TEE_PRIVATE_H*/
|
#endif /*TEE_PRIVATE_H*/
|
||||||
|
|
|
@ -53,6 +53,9 @@ static void tee_shm_release(struct tee_shm *shm)
|
||||||
kfree(shm->pages);
|
kfree(shm->pages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shm->ctx)
|
||||||
|
teedev_ctx_put(shm->ctx);
|
||||||
|
|
||||||
kfree(shm);
|
kfree(shm);
|
||||||
|
|
||||||
tee_device_put(teedev);
|
tee_device_put(teedev);
|
||||||
|
@ -187,6 +190,7 @@ struct tee_shm *__tee_shm_alloc(struct tee_context *ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
|
teedev_ctx_get(ctx);
|
||||||
mutex_lock(&teedev->mutex);
|
mutex_lock(&teedev->mutex);
|
||||||
list_add_tail(&shm->link, &ctx->list_shm);
|
list_add_tail(&shm->link, &ctx->list_shm);
|
||||||
mutex_unlock(&teedev->mutex);
|
mutex_unlock(&teedev->mutex);
|
||||||
|
@ -253,6 +257,8 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr,
|
||||||
return ERR_PTR(-ENOTSUPP);
|
return ERR_PTR(-ENOTSUPP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
teedev_ctx_get(ctx);
|
||||||
|
|
||||||
shm = kzalloc(sizeof(*shm), GFP_KERNEL);
|
shm = kzalloc(sizeof(*shm), GFP_KERNEL);
|
||||||
if (!shm) {
|
if (!shm) {
|
||||||
ret = ERR_PTR(-ENOMEM);
|
ret = ERR_PTR(-ENOMEM);
|
||||||
|
@ -334,6 +340,7 @@ err:
|
||||||
kfree(shm->pages);
|
kfree(shm->pages);
|
||||||
}
|
}
|
||||||
kfree(shm);
|
kfree(shm);
|
||||||
|
teedev_ctx_put(ctx);
|
||||||
tee_device_put(teedev);
|
tee_device_put(teedev);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/idr.h>
|
#include <linux/idr.h>
|
||||||
|
#include <linux/kref.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/tee.h>
|
#include <linux/tee.h>
|
||||||
|
|
||||||
|
@ -42,11 +43,17 @@ struct tee_shm_pool;
|
||||||
* @teedev: pointer to this drivers struct tee_device
|
* @teedev: pointer to this drivers struct tee_device
|
||||||
* @list_shm: List of shared memory object owned by this context
|
* @list_shm: List of shared memory object owned by this context
|
||||||
* @data: driver specific context data, managed by the driver
|
* @data: driver specific context data, managed by the driver
|
||||||
|
* @refcount: reference counter for this structure
|
||||||
|
* @releasing: flag that indicates if context is being released right now.
|
||||||
|
* It is needed to break circular dependency on context during
|
||||||
|
* shared memory release.
|
||||||
*/
|
*/
|
||||||
struct tee_context {
|
struct tee_context {
|
||||||
struct tee_device *teedev;
|
struct tee_device *teedev;
|
||||||
struct list_head list_shm;
|
struct list_head list_shm;
|
||||||
void *data;
|
void *data;
|
||||||
|
struct kref refcount;
|
||||||
|
bool releasing;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tee_param_memref {
|
struct tee_param_memref {
|
||||||
|
|
Loading…
Add table
Reference in a new issue