From 236b06ac63a86c9ec4818e8f827df0fdda950154 Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Thu, 21 Feb 2019 11:56:18 -0800 Subject: [PATCH] dma-buf: Add support to set a destructor on a dma-buf dma-buf destructor support is useful as it allows clients an opportunity to undo any attributes, such as security attributes, they have applied to the dma-buf's memory. The destructor is called when the dma-buf is freed, if the destructor returns an error the dma-buf's exporter release function is not called in order to ensure that memory which has not been properly cleaned up isn't returned to the system. Change-Id: If2173b23b441157b3638110f02e2ff90ab6ad1aa Signed-off-by: Liam Mark Signed-off-by: Swathi Sridhar [isaacm@codeaurora.org: resolve merge conflicts/qseecom redefinitions] Signed-off-by: Isaac J. Manjarres --- drivers/dma-buf/Kconfig | 15 +++++++++++++++ drivers/dma-buf/dma-buf.c | 29 ++++++++++++++++++++++++++++- drivers/misc/qseecom.c | 7 ------- include/linux/dma-buf.h | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 8 deletions(-) diff --git a/drivers/dma-buf/Kconfig b/drivers/dma-buf/Kconfig index 1dba8b54fb6d..f1b999622f35 100644 --- a/drivers/dma-buf/Kconfig +++ b/drivers/dma-buf/Kconfig @@ -41,6 +41,21 @@ config DEBUG_DMA_BUF_REF matching the get/put call stacks. This feature consumes extra memory in order to save the stack traces using STACKDEPOT. +config DMABUF_DESTRUCTOR_SUPPORT + bool "dmabuf destructor support" + default n + depends on DMA_SHARED_BUFFER + depends on QGKI + help + dma-buf destructor support is useful as it allows clients an + opportunity to undo any attributes, such as security attributes, + they have applied to the dma-buf's memory. + + The destructor is called when the dma-buf is freed, if the destructor + returns an error the dma-buf's exporter release function is not + called in order to ensure that memory which has not been properly + cleaned up isn't returned to the system + config UDMABUF bool "userspace dmabuf misc driver" default n diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index e0374937404c..5f9f30d8d035 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -54,10 +54,33 @@ static char *dmabuffs_dname(struct dentry *dentry, char *buffer, int buflen) dentry->d_name.name, ret > 0 ? name : ""); } +#ifdef CONFIG_DMABUF_DESTRUCTOR_SUPPORT +static int dma_buf_invoke_dtor(struct dma_buf *dmabuf) +{ + int ret = 0; + + if (dmabuf->dtor) { + ret = dmabuf->dtor(dmabuf, dmabuf->dtor_data); + if (ret < 0) + pr_warn_ratelimited("Leaking dmabuf ino: %ld because destructor failed error: %d\n", + file_inode(dmabuf->file)->i_ino, + ret); + } + + return ret; +} +#else +static inline int dma_buf_invoke_dtor(struct dma_buf *dmabuf) +{ + return 0; +} +#endif + static void dma_buf_release(struct dentry *dentry) { struct msm_dma_buf *msm_dma_buf; struct dma_buf *dmabuf; + int dtor_ret = 0; dmabuf = dentry->d_fsdata; msm_dma_buf = to_msm_dma_buf(dmabuf); @@ -78,7 +101,11 @@ static void dma_buf_release(struct dentry *dentry) list_del(&dmabuf->list_node); mutex_unlock(&db_list.lock); - dmabuf->ops->release(dmabuf); + dtor_ret = dma_buf_invoke_dtor(dmabuf); + + if (!dtor_ret) + dmabuf->ops->release(dmabuf); + dma_buf_ref_destroy(msm_dma_buf); if (dmabuf->resv == (struct dma_resv *)&dmabuf[1]) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 4ecaa95d060d..199e919a5930 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -1229,13 +1229,6 @@ exit: return ret; } -typedef int (*dma_buf_destructor)(struct dma_buf *dmabuf, void *dtor_data); -static void dma_buf_set_destructor(struct dma_buf *dmabuf, - dma_buf_destructor dtor, - void *dtor_data) -{ -} - static int qseecom_destroy_bridge_callback( struct dma_buf *dmabuf, void *dtor_data) { diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 3384c77e2e7b..5f46e7a7a63f 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -350,6 +350,18 @@ struct dma_buf_ops { int (*get_flags)(struct dma_buf *dmabuf, unsigned long *flags); }; +/** + * dma_buf_destructor - dma-buf destructor function + * @dmabuf: [in] pointer to dma-buf + * @dtor_data: [in] destructor data associated with this buffer + * + * The dma-buf destructor which is called when the dma-buf is freed. + * + * If the destructor returns an error the dma-buf's exporter release function + * won't be called. + */ +typedef int (*dma_buf_destructor)(struct dma_buf *dmabuf, void *dtor_data); + /** * struct dma_buf - shared buffer object * @size: size of the buffer @@ -394,6 +406,10 @@ struct dma_buf { struct list_head list_node; void *priv; struct dma_resv *resv; +#ifdef CONFIG_DMABUF_DESTRUCTOR_SUPPORT + dma_buf_destructor dtor; + void *dtor_data; +#endif /* poll support */ wait_queue_head_t poll; @@ -537,4 +553,27 @@ void dma_buf_vunmap(struct dma_buf *, void *vaddr); int dma_buf_get_flags(struct dma_buf *dmabuf, unsigned long *flags); int dma_buf_get_uuid(struct dma_buf *dmabuf, uuid_t *uuid); +#ifdef CONFIG_DMABUF_DESTRUCTOR_SUPPORT +/** + * dma_buf_set_destructor - set the dma-buf's destructor + * @dmabuf: [in] pointer to dma-buf + * @dma_buf_destructor [in] the destructor function + * @dtor_data: [in] destructor data associated with this buffer + */ +static inline int dma_buf_set_destructor(struct dma_buf *dmabuf, + dma_buf_destructor dtor, + void *dtor_data) +{ + dmabuf->dtor = dtor; + dmabuf->dtor_data = dtor_data; + return 0; +} +#else +static inline int dma_buf_set_destructor(struct dma_buf *dmabuf, + dma_buf_destructor dtor, + void *dtor_data) +{ + return -ENOTSUPP; +} +#endif #endif /* __DMA_BUF_H__ */