Hi Sumit, Thank you so much for the comemnts :). On 11/23/2024 9:32 PM, Sumit Garg wrote: > Hi Amirreza, > > Thanks for proposing this. > > On Fri, 22 Nov 2024 at 06:38, Amirreza Zarrabi > <quic_azarrabi@xxxxxxxxxxx> wrote: >> >> >> On 11/21/2024 11:08 PM, Jens Wiklander wrote: >> >> Hi Jens, >> >>> Hi Amirreza, >>> >>> On Thu, Nov 21, 2024 at 2:37 AM Amirreza Zarrabi >>> <quic_azarrabi@xxxxxxxxxxx> wrote: >>>> >>>> The default context has a lifespan similar to the tee_device. > > Since it's associated with tee_device context, let's call it obvious > via renaming it as device context instead (s/def_ctx/dev_ctx/ in this > patch). > Make sense, I'll rename it. >>>> It is used as a context for shared memory if the context to which the >>>> shared memory belongs is released, making the tee_shm an orphan. >>>> This allows the driver implementing shm_unregister to safely make >>>> subsequent calls, such as to a supplicant if needed. >>>> >>>> It also enables users to free the shared memory while the driver is >>>> blocked on unregister_tee_device safely. >>>> >>>> Preferably, this should be used for all driver internal uses, using >>>> teedev_get_def_context rather than calling teedev_open. > > Makes sense to me. > >>>> >>>> Signed-off-by: Amirreza Zarrabi <quic_azarrabi@xxxxxxxxxxx> >>>> --- >>>> drivers/tee/optee/core.c | 2 +- >>>> drivers/tee/optee/ffa_abi.c | 2 +- >>>> drivers/tee/optee/smc_abi.c | 2 +- >>>> drivers/tee/tee_core.c | 83 +++++++++++++++++++++++++++++---------------- >>>> drivers/tee/tee_private.h | 3 -- >>>> drivers/tee/tee_shm.c | 18 ++-------- >>>> include/linux/tee_core.h | 15 ++++++++ >>>> include/linux/tee_drv.h | 7 ---- >>>> 8 files changed, 73 insertions(+), 59 deletions(-) >>>> >>>> diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c >>>> index c75fddc83576..78d43d0c8014 100644 >>>> --- a/drivers/tee/optee/core.c >>>> +++ b/drivers/tee/optee/core.c >>>> @@ -173,7 +173,7 @@ void optee_remove_common(struct optee *optee) >>>> >>>> optee_notif_uninit(optee); >>>> optee_shm_arg_cache_uninit(optee); >>>> - teedev_close_context(optee->ctx); >>>> + >>>> /* >>>> * The two devices have to be unregistered before we can free the >>>> * other resources. >>>> diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c >>>> index f3af5666bb11..6ad94f0788ad 100644 >>>> --- a/drivers/tee/optee/ffa_abi.c >>>> +++ b/drivers/tee/optee/ffa_abi.c >>>> @@ -949,7 +949,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev) >>>> optee_shm_arg_cache_init(optee, arg_cache_flags); >>>> mutex_init(&optee->rpmb_dev_mutex); >>>> ffa_dev_set_drvdata(ffa_dev, optee); >>>> - ctx = teedev_open(optee->teedev); >>>> + ctx = teedev_get_def_context(optee->teedev); >>>> if (IS_ERR(ctx)) { >>>> rc = PTR_ERR(ctx); >>>> goto err_rhashtable_free; >>>> diff --git a/drivers/tee/optee/smc_abi.c b/drivers/tee/optee/smc_abi.c >>>> index e9456e3e74cc..c77a3e631d04 100644 >>>> --- a/drivers/tee/optee/smc_abi.c >>>> +++ b/drivers/tee/optee/smc_abi.c >>>> @@ -1722,7 +1722,7 @@ static int optee_probe(struct platform_device *pdev) >>>> mutex_init(&optee->rpmb_dev_mutex); >>>> >>>> platform_set_drvdata(pdev, optee); >>>> - ctx = teedev_open(optee->teedev); >>>> + ctx = teedev_get_def_context(optee->teedev); >>>> if (IS_ERR(ctx)) { >>>> rc = PTR_ERR(ctx); >>>> goto err_supp_uninit; >>>> diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c >>>> index 93f3b330aec8..805e1336089d 100644 >>>> --- a/drivers/tee/tee_core.c >>>> +++ b/drivers/tee/tee_core.c >>>> @@ -57,7 +57,6 @@ struct tee_context *teedev_open(struct tee_device *teedev) >>>> goto err; >>>> } >>>> >>>> - kref_init(&ctx->refcount); >>>> ctx->teedev = teedev; >>>> INIT_LIST_HEAD(&ctx->list_shm); >>>> rc = teedev->desc->ops->open(ctx); >>>> @@ -73,36 +72,43 @@ struct tee_context *teedev_open(struct tee_device *teedev) >>>> } >>>> EXPORT_SYMBOL_GPL(teedev_open); >>>> >>>> -void teedev_ctx_get(struct tee_context *ctx) >>>> +struct tee_context *teedev_get_def_context(struct tee_device *teedev) >>>> { >>>> - if (ctx->releasing) >>>> - return; >>>> + int rc; >>>> + struct tee_context *ctx = &teedev->def_ctx; >>>> >>>> - kref_get(&ctx->refcount); >>>> -} >>>> + ctx->teedev = teedev; >>>> + INIT_LIST_HEAD(&ctx->list_shm); >>>> + rc = teedev->desc->ops->open(ctx); >>>> + if (rc) >>>> + return ERR_PTR(rc); >>> >>> I think ctx->teedev and ctx->list_shm must always be initialized or >>> &teedev->def_ctx can't be used in teedev_close_context(). >> >> True, but &teedev->def_ctx is never used in teedev_close_context(). >> The closing of the &teedev->def_ctx simply ignored. So once opened, >> &teedev->def_ctx will always remain open until the tee_device is alive. >> >>> We could initialize teedev->def_ctx on the first call to teedev_open() >>> on that tee_device. We need a way to tell the >>> teedev->desc->ops->open() to the backed driver that it's initializing >>> the default context though, or optee_open() can't handle the >>> tee-supplicant case properly. >>> >> >> That's a good point. This way, it is guaranteed that there is one def_ctx >> per teedev. There should be a way to tell the open() callback that it is >> a def_ctx, so it is not registered as a supplicant context. >> >> >>> Should we allow this function to be called more than once for each teedev? >> >> Yes, moving to teedev_open() will fix the issue. >> >>> Do we need serialization in this function if it's called after the >>> driver is probed? >>> >> >> True. I'll make sure there is no race. >> >>>> >>>> -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); >>>> + return ctx; >>>> } >>>> +EXPORT_SYMBOL_GPL(teedev_get_def_context); >>>> >>>> -void teedev_ctx_put(struct tee_context *ctx) >>>> +void teedev_close_context(struct tee_context *ctx) >>>> { >>>> - if (ctx->releasing) >>>> + struct tee_device *teedev = ctx->teedev; >>>> + struct tee_shm *shm; >>>> + >>>> + if (ctx == &teedev->def_ctx) >>>> return; >>>> >>>> - kref_put(&ctx->refcount, teedev_ctx_release); >>>> -} >>>> + teedev->desc->ops->release(ctx); >>>> >>>> -void teedev_close_context(struct tee_context *ctx) >>>> -{ >>>> - struct tee_device *teedev = ctx->teedev; >>>> + mutex_lock(&teedev->mutex); >>>> + list_for_each_entry(shm, &ctx->list_shm, link) { >>>> + /* Context released. However, shm still holding a teedev reference. >>>> + * Replace shm->ctx with the default context so that tee_shm_get_from_id() >>>> + * fails (i.e. it is not accessible from userspace) but shm still >>>> + * holds a valid context for further clean up, e.g. shm_unregister(). >>>> + */ >>> >>> /* >>> * Please format >>> * multiline comments >>> * like this. Please >>> * keep the lines at >>> * max 80 columns >>> * here and at other >>> * places in the patch- >>> * set. >>> */ >>> >> >> Ack. >> >>>> + shm->ctx = &teedev->def_ctx; >>> >>> shm->ctx will always point to a valid context, even if it is the >>> default context. It seems that we can always get hold of the correct >>> teedev via shm->ctx->teedev. Do we need "tee: revert removal of >>> redundant teedev in struct tee_shm"? >>> >> >> It was there in case we wanted to use NULL, but with def_ctx, it is not >> necessary. I am withdrawing that commit. :). >> >>> Shouldn't the shm be removed from the ctx->list_shm and be moved to >>> teedev->def_ctx.list_shm? > > +1 > Ack. >>> >> >> Not really. If we put shm in the teedev->def_ctx.list_shm, by the time >> we are closing the def_ctx, the list is guaranteed to be empty. >> >> However, I understand it is cleaner and more consistent to do that rather >> than making changes to tee_shm_put(). >> >> I'll do it. >> >>>> + } >>>> + mutex_unlock(&teedev->mutex); >>>> >>>> - teedev_ctx_put(ctx); >>>> + kfree(ctx); >>>> tee_device_put(teedev); >>>> } >>>> EXPORT_SYMBOL_GPL(teedev_close_context); >>>> @@ -946,6 +952,8 @@ struct tee_device *tee_device_alloc(const struct tee_desc *teedesc, >>>> >>>> teedev->desc = teedesc; >>>> teedev->pool = pool; >>>> + /* Only open default context when teedev_get_def_context() called. */ >>>> + teedev->def_ctx.teedev = NULL; > > Why don't you open the device context here only? This will associate > it automatically with teedev lifespan and then > teedev_get_def_context() will just return a reference to that. > > -Sumit > So my assumption is that the tee_devic_alloc() is called as part of the driver initialization; there is no guarantee that at this time the driver is actually ready to accept any open() callback. Best Regards, Amir >>>> >>>> return teedev; >>>> err_devt: >>>> @@ -1027,16 +1035,31 @@ EXPORT_SYMBOL_GPL(tee_device_register); >>>> >>>> void tee_device_put(struct tee_device *teedev) >>>> { >>>> - mutex_lock(&teedev->mutex); >>>> - /* Shouldn't put in this state */ >>>> - if (!WARN_ON(!teedev->desc)) { >>>> - teedev->num_users--; >>>> - if (!teedev->num_users) { >>>> - teedev->desc = NULL; >>>> - complete(&teedev->c_no_users); >>>> - } >>>> + const struct tee_desc *desc; >>>> + >>>> + scoped_guard(mutex, &teedev->mutex) { >>>> + desc = teedev->desc; >>>> + >>>> + /* Shouldn't put in this state */ >>>> + if (WARN_ON(!desc)) >>>> + return; >>>> + >>>> + /* If there is still users for teedev */ >>>> + if (--teedev->num_users) >>> >>> Please do teedev->num_users-- first and then check. It makes the code >>> easier to read. >> >> Ack. >> >>> >>>> + return; >>>> + >>>> + /* tee_device_unregister() has been called and there is no >>>> + * user in userspace or kernel, including orphan shm for teedev. >>>> + * Set teedev->desc to NULL, so that teedev can not be reused. >>>> + */ >>>> + teedev->desc = NULL; >>>> } >>>> - mutex_unlock(&teedev->mutex); >>>> + >>>> + /* Release the default context */ >>>> + desc->ops->release(&teedev->def_ctx); >>> >>> This should only be done if teedev->def_ctx has been initialized. >>> >> >> Ack. >> >>> Cheers, >>> Jens >> >> Thank you very much for your comments :). >> If you're okay with introducing def_ctx, I'll prepare a complete patchset >> with all the details. >> >> Best Regards, >> Amir >> >> >>> >>>> + teedev->def_ctx.teedev = NULL; >>>> + >>>> + complete(&teedev->c_no_users); >>>> } >>>> >>>> bool tee_device_get(struct tee_device *teedev) >>>> diff --git a/drivers/tee/tee_private.h b/drivers/tee/tee_private.h >>>> index 9bc50605227c..6c7bcc308958 100644 >>>> --- a/drivers/tee/tee_private.h >>>> +++ b/drivers/tee/tee_private.h >>>> @@ -17,9 +17,6 @@ int tee_shm_get_fd(struct tee_shm *shm); >>>> bool tee_device_get(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); >>>> - >>>> struct tee_shm *tee_shm_alloc_user_buf(struct tee_context *ctx, size_t size); >>>> struct tee_shm *tee_shm_register_user_buf(struct tee_context *ctx, >>>> unsigned long addr, size_t length); >>>> diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c >>>> index c0164c0f4a01..f07274291edf 100644 >>>> --- a/drivers/tee/tee_shm.c >>>> +++ b/drivers/tee/tee_shm.c >>>> @@ -59,8 +59,6 @@ static void tee_shm_release(struct tee_shm *shm) >>>> release_registered_pages(shm); >>>> } >>>> >>>> - teedev_ctx_put(shm->ctx); >>>> - >>>> kfree(shm); >>>> >>>> tee_device_put(teedev); >>>> @@ -93,13 +91,6 @@ static struct tee_shm *shm_alloc_helper(struct tee_context *ctx, size_t size, >>>> shm->flags = flags; >>>> shm->teedev = teedev; >>>> shm->id = id; >>>> - >>>> - /* >>>> - * We're assigning this as it is needed if the shm is to be >>>> - * registered. If this function returns OK then the caller expected >>>> - * to call teedev_ctx_get() or clear shm->ctx in case it's not >>>> - * needed any longer. >>>> - */ >>>> shm->ctx = ctx; >>>> >>>> rc = teedev->pool->ops->alloc(teedev->pool, shm, size, align); >>>> @@ -112,7 +103,6 @@ static struct tee_shm *shm_alloc_helper(struct tee_context *ctx, size_t size, >>>> list_add_tail(&shm->link, &ctx->list_shm); >>>> mutex_unlock(&teedev->mutex); >>>> >>>> - teedev_ctx_get(ctx); >>>> return shm; >>>> err_kfree: >>>> kfree(shm); >>>> @@ -295,12 +285,10 @@ register_shm_helper(struct tee_context *ctx, struct iov_iter *iter, u32 flags, >>>> goto err_dev_put; >>>> } >>>> >>>> - teedev_ctx_get(ctx); >>>> - >>>> shm = kzalloc(sizeof(*shm), GFP_KERNEL); >>>> if (!shm) { >>>> ret = ERR_PTR(-ENOMEM); >>>> - goto err_ctx_put; >>>> + goto err_dev_put; >>>> } >>>> >>>> refcount_set(&shm->refcount, 1); >>>> @@ -313,7 +301,7 @@ register_shm_helper(struct tee_context *ctx, struct iov_iter *iter, u32 flags, >>>> num_pages = iov_iter_npages(iter, INT_MAX); >>>> if (!num_pages) { >>>> ret = ERR_PTR(-ENOMEM); >>>> - goto err_ctx_put; >>>> + goto err_dev_put; >>>> } >>>> >>>> shm->pages = kcalloc(num_pages, sizeof(*shm->pages), GFP_KERNEL); >>>> @@ -361,8 +349,6 @@ register_shm_helper(struct tee_context *ctx, struct iov_iter *iter, u32 flags, >>>> kfree(shm->pages); >>>> err_free_shm: >>>> kfree(shm); >>>> -err_ctx_put: >>>> - teedev_ctx_put(ctx); >>>> err_dev_put: >>>> tee_device_put(teedev); >>>> return ret; >>>> diff --git a/include/linux/tee_core.h b/include/linux/tee_core.h >>>> index a38494d6b5f4..13393ddac530 100644 >>>> --- a/include/linux/tee_core.h >>>> +++ b/include/linux/tee_core.h >>>> @@ -44,6 +44,7 @@ >>>> * @idr: register of user space shared memory objects allocated or >>>> * registered on this device >>>> * @pool: shared memory pool >>>> + * @def_ctx: default context used if there is no context available, e.g. internal driver calls. >>>> */ >>>> struct tee_device { >>>> char name[TEE_MAX_DEV_NAME_LEN]; >>>> @@ -60,6 +61,7 @@ struct tee_device { >>>> >>>> struct idr idr; >>>> struct tee_shm_pool *pool; >>>> + struct tee_context def_ctx; >>>> }; >>>> >>>> /** >>>> @@ -309,6 +311,19 @@ static inline bool tee_param_is_memref(struct tee_param *param) >>>> */ >>>> struct tee_context *teedev_open(struct tee_device *teedev); >>>> >>>> +/** >>>> + * teedev_get_def_context() - Get default context for a struct tee_device >>>> + * @teedev: Device to open >>>> + * >>>> + * Unlike a context that returned from teedev_open(), the default context is static >>>> + * and available as long as @teedev has a user ''other then this context''. This context >>>> + * can be used for driver internal operation and clean up where a context should be >>>> + * available, while tee_device_unregister() is waiting for other users to go away. >>>> + * >>>> + * @return a pointer to struct tee_context on success or an ERR_PTR on failure. >>>> + */ >>>> +struct tee_context *teedev_get_def_context(struct tee_device *teedev); >>>> + >>>> /** >>>> * teedev_close_context() - closes a struct tee_context >>>> * @ctx: The struct tee_context to close >>>> diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h >>>> index 1b57cddfecc8..9633e14ba484 100644 >>>> --- a/include/linux/tee_drv.h >>>> +++ b/include/linux/tee_drv.h >>>> @@ -7,7 +7,6 @@ >>>> #define __TEE_DRV_H >>>> >>>> #include <linux/device.h> >>>> -#include <linux/kref.h> >>>> #include <linux/list.h> >>>> #include <linux/mod_devicetable.h> >>>> #include <linux/tee.h> >>>> @@ -25,10 +24,6 @@ struct tee_device; >>>> * @teedev: pointer to this drivers struct tee_device >>>> * @list_shm: List of shared memory object owned by this context >>>> * @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. >>>> * @supp_nowait: flag that indicates that requests in this context should not >>>> * wait for tee-supplicant daemon to be started if not present >>>> * and just return with an error code. It is needed for requests >>>> @@ -41,8 +36,6 @@ struct tee_context { >>>> struct tee_device *teedev; >>>> struct list_head list_shm; >>>> void *data; >>>> - struct kref refcount; >>>> - bool releasing; >>>> bool supp_nowait; >>>> bool cap_memref_null; >>>> }; >>>> >>>> -- >>>> 2.34.1 >>>>