[PATCH 2/2] dma-mapping: benchmark: prevent potential kthread hang

Fedor Pchelkin posted 2 patches 1 year, 7 months ago
[PATCH 2/2] dma-mapping: benchmark: prevent potential kthread hang
Posted by Fedor Pchelkin 1 year, 7 months ago
If some of kthreads executing map_benchmark_thread() return with an error
code (e.g. due to a memory allocation failure), then the next kthreads in
the array are not stopped and potentially loop for indefinite time.

Call kthread_stop() for each started thread as map_benchmark_thread()
expects that happening in order to exit.

Found by Linux Verification Center (linuxtesting.org).

Fixes: 65789daa8087 ("dma-mapping: add benchmark support for streaming DMA APIs")
Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
---
 kernel/dma/map_benchmark.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/kernel/dma/map_benchmark.c b/kernel/dma/map_benchmark.c
index ea938bc6c7e3..7e39a4690331 100644
--- a/kernel/dma/map_benchmark.c
+++ b/kernel/dma/map_benchmark.c
@@ -140,13 +140,17 @@ static int do_map_benchmark(struct map_benchmark_data *map)
 
 	msleep_interruptible(map->bparam.seconds * 1000);
 
-	/* wait for the completion of benchmark threads */
+	/* wait for the completion of all started benchmark threads */
 	for (i = 0; i < threads; i++) {
-		ret = kthread_stop(tsk[i]);
-		if (ret)
-			goto out;
+		int kthread_ret = kthread_stop(tsk[i]);
+
+		if (kthread_ret)
+			ret = kthread_ret;
 	}
 
+	if (ret)
+		goto out;
+
 	loops = atomic64_read(&map->loops);
 	if (likely(loops > 0)) {
 		u64 map_variance, unmap_variance;
-- 
2.45.0
Re: [PATCH 2/2] dma-mapping: benchmark: prevent potential kthread hang
Posted by Barry Song 1 year, 7 months ago
On Fri, May 3, 2024 at 4:29 AM Fedor Pchelkin <pchelkin@ispras.ru> wrote:
>
> If some of kthreads executing map_benchmark_thread() return with an error
> code (e.g. due to a memory allocation failure), then the next kthreads in
> the array are not stopped and potentially loop for indefinite time.
>
> Call kthread_stop() for each started thread as map_benchmark_thread()
> expects that happening in order to exit.
>
> Found by Linux Verification Center (linuxtesting.org).
>
> Fixes: 65789daa8087 ("dma-mapping: add benchmark support for streaming DMA APIs")
> Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
> ---
>  kernel/dma/map_benchmark.c | 12 ++++++++----
>  1 file changed, 8 insertions(+), 4 deletions(-)
>
> diff --git a/kernel/dma/map_benchmark.c b/kernel/dma/map_benchmark.c
> index ea938bc6c7e3..7e39a4690331 100644
> --- a/kernel/dma/map_benchmark.c
> +++ b/kernel/dma/map_benchmark.c
> @@ -140,13 +140,17 @@ static int do_map_benchmark(struct map_benchmark_data *map)
>
>         msleep_interruptible(map->bparam.seconds * 1000);
>
> -       /* wait for the completion of benchmark threads */
> +       /* wait for the completion of all started benchmark threads */
>         for (i = 0; i < threads; i++) {
> -               ret = kthread_stop(tsk[i]);
> -               if (ret)
> -                       goto out;
> +               int kthread_ret = kthread_stop(tsk[i]);
> +
> +               if (kthread_ret)
> +                       ret = kthread_ret;
>         }
>
> +       if (ret)
> +               goto out;
> +

do we still need to do copy_to_user(argp, &map->bparam, sizeof(map->bparam)
after  do_map_benchmark(map) fails?
do we also need the below?
diff --git a/kernel/dma/map_benchmark.c b/kernel/dma/map_benchmark.c
index 02205ab53b7e..28ca165cb62c 100644
--- a/kernel/dma/map_benchmark.c
+++ b/kernel/dma/map_benchmark.c
@@ -252,6 +252,9 @@ static long map_benchmark_ioctl(struct file *file,
unsigned int cmd,
                 * dma_mask changed by benchmark
                 */
                dma_set_mask(map->dev, old_dma_mask);
+
+               if (ret)
+                       return ret;
                break;
        default:
                return -EINVAL;


>         loops = atomic64_read(&map->loops);
>         if (likely(loops > 0)) {
>                 u64 map_variance, unmap_variance;
> --
> 2.45.0
>
>
Re: [PATCH 2/2] dma-mapping: benchmark: prevent potential kthread hang
Posted by Fedor Pchelkin 1 year, 7 months ago
On Fri, 03. May 13:44, Barry Song wrote:
> On Fri, May 3, 2024 at 4:29 AM Fedor Pchelkin <pchelkin@ispras.ru> wrote:
> 

[...]

> do we still need to do copy_to_user(argp, &map->bparam, sizeof(map->bparam)
> after  do_map_benchmark(map) fails?
> do we also need the below?
> diff --git a/kernel/dma/map_benchmark.c b/kernel/dma/map_benchmark.c
> index 02205ab53b7e..28ca165cb62c 100644
> --- a/kernel/dma/map_benchmark.c
> +++ b/kernel/dma/map_benchmark.c
> @@ -252,6 +252,9 @@ static long map_benchmark_ioctl(struct file *file,
> unsigned int cmd,
>                  * dma_mask changed by benchmark
>                  */
>                 dma_set_mask(map->dev, old_dma_mask);
> +
> +               if (ret)
> +                       return ret;
>                 break;
>         default:
>                 return -EINVAL;
> 
> 

Good point, thank you! If benchmark failed, nothing new to be copied back
to user, indeed.

I'll add this as the third patch of the series and post v2.