[PATCH V1] dma-mapping: Set dma_mem pointer as NULL after it's freed

joakim.zhang@cixtech.com posted 1 patch 2 years ago
There is a newer version of this series
kernel/dma/coherent.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
[PATCH V1] dma-mapping: Set dma_mem pointer as NULL after it's freed
Posted by joakim.zhang@cixtech.com 2 years ago
From: Joakim Zhang <joakim.zhang@cixtech.com>

Reproduced with below sequence:
dma_declare_coherent_memory()->dma_release_coherent_memory()
->dma_declare_coherent_memory()->"return -EBUSY" error

It will return -EBUSY from the dma_assign_coherent_memory()
in dma_declare_coherent_memory(), the reason is that dev->dma_mem
pointer has not been set to NULL after it's freed.

Go through the driver, found there is a issue in
rmem_dma_device_release(), the reserved memory has not been
freed before "dev->dma_mem = NULL;". So if user call
of_reserved_mem_device_release(), will not free reserved mem
in fact.

Fixes: cf65a0f6f6ff ("dma-mapping: move all DMA mapping code to kernel/dma")
Signed-off-by: Joakim Zhang <joakim.zhang@cixtech.com>
---
 kernel/dma/coherent.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/kernel/dma/coherent.c b/kernel/dma/coherent.c
index c21abc77c53e..602e055fc1bf 100644
--- a/kernel/dma/coherent.c
+++ b/kernel/dma/coherent.c
@@ -132,8 +132,10 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
 
 void dma_release_coherent_memory(struct device *dev)
 {
-	if (dev)
+	if (dev) {
 		_dma_release_coherent_memory(dev->dma_mem);
+		dev->dma_mem = NULL;
+	}
 }
 
 static void *__dma_alloc_from_coherent(struct device *dev,
@@ -349,8 +351,10 @@ static int rmem_dma_device_init(struct reserved_mem *rmem, struct device *dev)
 static void rmem_dma_device_release(struct reserved_mem *rmem,
 				    struct device *dev)
 {
-	if (dev)
+	if (dev) {
+		_dma_release_coherent_memory(rmem->priv);
 		dev->dma_mem = NULL;
+	}
 }
 
 static const struct reserved_mem_ops rmem_dma_ops = {
-- 
2.25.1
回复: [PATCH V1] dma-mapping: Set dma_mem pointer as NULL after it's freed
Posted by Joakim Zhang 2 years ago
Hi maintainers,

> -----邮件原件-----
> 发件人: Joakim Zhang <joakim.zhang@cixtech.com>
> 发送时间: 2023年12月12日 13:22
> 收件人: hch@lst.de; m.szyprowski@samsung.com; robin.murphy@arm.com
> 抄送: iommu@lists.linux.dev; linux-kernel@vger.kernel.org;
> cix-kernel-upstream <cix-kernel-upstream@cixtech.com>; Joakim Zhang
> <joakim.zhang@cixtech.com>
> 主题: [PATCH V1] dma-mapping: Set dma_mem pointer as NULL after it's freed
> 
> From: Joakim Zhang <joakim.zhang@cixtech.com>
> 
> Reproduced with below sequence:
> dma_declare_coherent_memory()->dma_release_coherent_memory()
> ->dma_declare_coherent_memory()->"return -EBUSY" error
> 
> It will return -EBUSY from the dma_assign_coherent_memory() in
> dma_declare_coherent_memory(), the reason is that dev->dma_mem pointer
> has not been set to NULL after it's freed.
> 
> Go through the driver, found there is a issue in rmem_dma_device_release(),
> the reserved memory has not been freed before "dev->dma_mem = NULL;". So
> if user call of_reserved_mem_device_release(), will not free reserved mem in
> fact.
> 
> Fixes: cf65a0f6f6ff ("dma-mapping: move all DMA mapping code to
> kernel/dma")
> Signed-off-by: Joakim Zhang <joakim.zhang@cixtech.com>
> ---
>  kernel/dma/coherent.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
> 
> diff --git a/kernel/dma/coherent.c b/kernel/dma/coherent.c index
> c21abc77c53e..602e055fc1bf 100644
> --- a/kernel/dma/coherent.c
> +++ b/kernel/dma/coherent.c
> @@ -132,8 +132,10 @@ int dma_declare_coherent_memory(struct device
> *dev, phys_addr_t phys_addr,
> 
>  void dma_release_coherent_memory(struct device *dev)  {
> -	if (dev)
> +	if (dev) {
>  		_dma_release_coherent_memory(dev->dma_mem);
> +		dev->dma_mem = NULL;
> +	}
>  }
> 
>  static void *__dma_alloc_from_coherent(struct device *dev, @@ -349,8
> +351,10 @@ static int rmem_dma_device_init(struct reserved_mem *rmem,
> struct device *dev)  static void rmem_dma_device_release(struct
> reserved_mem *rmem,
>  				    struct device *dev)
>  {
> -	if (dev)
> +	if (dev) {
> +		_dma_release_coherent_memory(rmem->priv);

Per my understanding, this change may not need, since this is reserved memory from device tree, once calling of_reserved_mem_device_init_by_idx() to initialize, it will be added to "of_rmem_assigned_device_list" list. Even calling of_reserved_mem_device_release() to release it, it's unnecessary to unremap and free it, since it's "reserved memory", only need to unbind from the device. When we call of_reserved_mem_device_init_by_idx() again, just need to find it from the list then bind it.

Right?

Joakim

>  		dev->dma_mem = NULL;
> +	}
>  }
> 
>  static const struct reserved_mem_ops rmem_dma_ops = {
> --
> 2.25.1