[PATCH 2/6] workqueue: Protect wq_unbound_cpumask with wq_pool_attach_mutex in init_rescuer()

Lai Jiangshan posted 6 patches 1 year, 5 months ago
There is a newer version of this series
[PATCH 2/6] workqueue: Protect wq_unbound_cpumask with wq_pool_attach_mutex in init_rescuer()
Posted by Lai Jiangshan 1 year, 5 months ago
From: Lai Jiangshan <jiangshan.ljs@antgroup.com>

wq_unbound_cpumask can be possibly changed without wq_pool_attach_mutex
or wq_pool_mutex held in init_rescuer().

Use wq_pool_attach_mutex to protect it.

Fixes: 49584bb8ddbe("workqueue: Bind unbound workqueue rescuer to wq_unbound_cpumask")
Signed-off-by: Lai Jiangshan <jiangshan.ljs@antgroup.com>
---
 kernel/workqueue.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index c738b3024cc2..cf1a129eb547 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -5533,6 +5533,9 @@ static int init_rescuer(struct workqueue_struct *wq)
 		return ret;
 	}
 
+	/* lock wq_pool_attach_mutex for wq_unbound_cpumask */
+	mutex_lock(&wq_pool_attach_mutex);
+
 	wq->rescuer = rescuer;
 	if (wq->flags & WQ_UNBOUND)
 		kthread_bind_mask(rescuer->task, wq_unbound_cpumask);
@@ -5540,6 +5543,8 @@ static int init_rescuer(struct workqueue_struct *wq)
 		kthread_bind_mask(rescuer->task, cpu_possible_mask);
 	wake_up_process(rescuer->task);
 
+	mutex_unlock(&wq_pool_attach_mutex);
+
 	return 0;
 }
 
-- 
2.19.1.6.gb485710b
Re: [PATCH 2/6] workqueue: Protect wq_unbound_cpumask with wq_pool_attach_mutex in init_rescuer()
Posted by Tejun Heo 1 year, 5 months ago
Hello, Lai.

On Wed, Jul 03, 2024 at 11:38:51AM +0800, Lai Jiangshan wrote:
> @@ -5533,6 +5533,9 @@ static int init_rescuer(struct workqueue_struct *wq)
>  		return ret;
>  	}
>  
> +	/* lock wq_pool_attach_mutex for wq_unbound_cpumask */
> +	mutex_lock(&wq_pool_attach_mutex);
> +
>  	wq->rescuer = rescuer;
>  	if (wq->flags & WQ_UNBOUND)
>  		kthread_bind_mask(rescuer->task, wq_unbound_cpumask);
> @@ -5540,6 +5543,8 @@ static int init_rescuer(struct workqueue_struct *wq)
>  		kthread_bind_mask(rescuer->task, cpu_possible_mask);
>  	wake_up_process(rescuer->task);
>  
> +	mutex_unlock(&wq_pool_attach_mutex);
> +

Isn't that just protecting the reads on wq_unbound_cpumask? I don't
understand what this protects against. Shouldn't the interlocking be
something like "either new rescuer reads the updated cpumask or the
workqueue is already on the workqueue list"?

Thanks.

-- 
tejun
Re: [PATCH 2/6] workqueue: Protect wq_unbound_cpumask with wq_pool_attach_mutex in init_rescuer()
Posted by Waiman Long 1 year, 5 months ago
On 7/2/24 23:38, Lai Jiangshan wrote:
> From: Lai Jiangshan <jiangshan.ljs@antgroup.com>
>
> wq_unbound_cpumask can be possibly changed without wq_pool_attach_mutex
> or wq_pool_mutex held in init_rescuer().
>
> Use wq_pool_attach_mutex to protect it.
>
> Fixes: 49584bb8ddbe("workqueue: Bind unbound workqueue rescuer to wq_unbound_cpumask")
> Signed-off-by: Lai Jiangshan <jiangshan.ljs@antgroup.com>
> ---
>   kernel/workqueue.c | 5 +++++
>   1 file changed, 5 insertions(+)
>
> diff --git a/kernel/workqueue.c b/kernel/workqueue.c
> index c738b3024cc2..cf1a129eb547 100644
> --- a/kernel/workqueue.c
> +++ b/kernel/workqueue.c
> @@ -5533,6 +5533,9 @@ static int init_rescuer(struct workqueue_struct *wq)
>   		return ret;
>   	}
>   
> +	/* lock wq_pool_attach_mutex for wq_unbound_cpumask */
> +	mutex_lock(&wq_pool_attach_mutex);
> +
>   	wq->rescuer = rescuer;
>   	if (wq->flags & WQ_UNBOUND)
>   		kthread_bind_mask(rescuer->task, wq_unbound_cpumask);
> @@ -5540,6 +5543,8 @@ static int init_rescuer(struct workqueue_struct *wq)
>   		kthread_bind_mask(rescuer->task, cpu_possible_mask);
>   	wake_up_process(rescuer->task);
>   
> +	mutex_unlock(&wq_pool_attach_mutex);
> +
>   	return 0;
>   }
>   
Reviewed-by: Waiman Long <longman@redhat.com>

Thanks!