linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v3] workqueue: Introduce show_one_worker_pool and show_one_workqueue.
@ 2021-10-16  0:20 Imran Khan
  2021-10-19 18:41 ` Tejun Heo
  0 siblings, 1 reply; 3+ messages in thread
From: Imran Khan @ 2021-10-16  0:20 UTC (permalink / raw)
  To: tj, jiangshanlai, gregkh, jirislaby, rafael, pavel, len.brown
  Cc: linux-kernel, linux-pm

Currently show_workqueue_state shows the state of all workqueues and of
all worker pools. In certain cases we may need to dump state of only a
specific workqueue or worker pool. For example in destroy_workqueue we
only need to show state of the workqueue which is getting destroyed.

So rename show_workqueue_state to show_all_workqueues(to signify it
dumps state of all busy workqueues) and divide it into more granular
functions (show_one_workqueue and show_one_worker_pool), that would show
states of individual workqueues and worker pools and can be used in
cases such as the one mentioned above.

Also, as mentioned earlier, make destroy_workqueue dump data pertaining
to only the workqueue that is being destroyed and make user(s) of
earlier interface(show_workqueue_state), use new interface
(show_all_workqueues).

Signed-off-by: Imran Khan <imran.f.khan@oracle.com>
---
Changes in v3:
  - Address review comments regarding function names
  - Change users of show_workqueue_state to use show_all_workqueues

 drivers/tty/sysrq.c       |   2 +-
 include/linux/workqueue.h |   3 +-
 kernel/power/process.c    |   2 +-
 kernel/workqueue.c        | 148 +++++++++++++++++++++-----------------
 4 files changed, 88 insertions(+), 67 deletions(-)

diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index c911196ac893..8d0f07509ca7 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -296,7 +296,7 @@ static const struct sysrq_key_op sysrq_showregs_op = {
 static void sysrq_handle_showstate(int key)
 {
 	show_state();
-	show_workqueue_state();
+	show_all_workqueues();
 }
 static const struct sysrq_key_op sysrq_showstate_op = {
 	.handler	= sysrq_handle_showstate,
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 2ebef6b1a3d6..c48f86e38d89 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -470,7 +470,8 @@ extern bool workqueue_congested(int cpu, struct workqueue_struct *wq);
 extern unsigned int work_busy(struct work_struct *work);
 extern __printf(1, 2) void set_worker_desc(const char *fmt, ...);
 extern void print_worker_info(const char *log_lvl, struct task_struct *task);
-extern void show_workqueue_state(void);
+extern void show_all_workqueues(void);
+extern void show_one_workqueue(struct workqueue_struct *wq);
 extern void wq_worker_comm(char *buf, size_t size, struct task_struct *task);
 
 /**
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 37401c99b7d7..b7e7798637b8 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -94,7 +94,7 @@ static int try_to_freeze_tasks(bool user_only)
 		       todo - wq_busy, wq_busy);
 
 		if (wq_busy)
-			show_workqueue_state();
+			show_all_workqueues();
 
 		if (!wakeup || pm_debug_messages_on) {
 			read_lock(&tasklist_lock);
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 9a042a449002..dbdf14738ca6 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -375,6 +375,7 @@ EXPORT_SYMBOL_GPL(system_freezable_power_efficient_wq);
 static int worker_thread(void *__worker);
 static void workqueue_sysfs_unregister(struct workqueue_struct *wq);
 static void show_pwq(struct pool_workqueue *pwq);
+static void show_one_worker_pool(struct worker_pool *pool);
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/workqueue.h>
@@ -4447,7 +4448,7 @@ void destroy_workqueue(struct workqueue_struct *wq)
 			raw_spin_unlock_irq(&pwq->pool->lock);
 			mutex_unlock(&wq->mutex);
 			mutex_unlock(&wq_pool_mutex);
-			show_workqueue_state();
+			show_one_workqueue(wq);
 			return;
 		}
 		raw_spin_unlock_irq(&pwq->pool->lock);
@@ -4797,83 +4798,102 @@ static void show_pwq(struct pool_workqueue *pwq)
 }
 
 /**
- * show_workqueue_state - dump workqueue state
- *
- * Called from a sysrq handler or try_to_freeze_tasks() and prints out
- * all busy workqueues and pools.
+ * show_one_workqueue - dump state of specified workqueue
+ * @wq: workqueue whose state will be printed
  */
-void show_workqueue_state(void)
+void show_one_workqueue(struct workqueue_struct *wq)
 {
-	struct workqueue_struct *wq;
-	struct worker_pool *pool;
+	struct pool_workqueue *pwq;
+	bool idle = true;
 	unsigned long flags;
-	int pi;
-
-	rcu_read_lock();
-
-	pr_info("Showing busy workqueues and worker pools:\n");
-
-	list_for_each_entry_rcu(wq, &workqueues, list) {
-		struct pool_workqueue *pwq;
-		bool idle = true;
-
-		for_each_pwq(pwq, wq) {
-			if (pwq->nr_active || !list_empty(&pwq->inactive_works)) {
-				idle = false;
-				break;
-			}
-		}
-		if (idle)
-			continue;
-
-		pr_info("workqueue %s: flags=0x%x\n", wq->name, wq->flags);
 
-		for_each_pwq(pwq, wq) {
-			raw_spin_lock_irqsave(&pwq->pool->lock, flags);
-			if (pwq->nr_active || !list_empty(&pwq->inactive_works))
-				show_pwq(pwq);
-			raw_spin_unlock_irqrestore(&pwq->pool->lock, flags);
-			/*
-			 * We could be printing a lot from atomic context, e.g.
-			 * sysrq-t -> show_workqueue_state(). Avoid triggering
-			 * hard lockup.
-			 */
-			touch_nmi_watchdog();
+	for_each_pwq(pwq, wq) {
+		if (pwq->nr_active || !list_empty(&pwq->inactive_works)) {
+			idle = false;
+			break;
 		}
 	}
+	if (idle) /* Nothing to print for idle workqueue */
+		return;
 
-	for_each_pool(pool, pi) {
-		struct worker *worker;
-		bool first = true;
+	pr_info("workqueue %s: flags=0x%x\n", wq->name, wq->flags);
 
-		raw_spin_lock_irqsave(&pool->lock, flags);
-		if (pool->nr_workers == pool->nr_idle)
-			goto next_pool;
-
-		pr_info("pool %d:", pool->id);
-		pr_cont_pool_info(pool);
-		pr_cont(" hung=%us workers=%d",
-			jiffies_to_msecs(jiffies - pool->watchdog_ts) / 1000,
-			pool->nr_workers);
-		if (pool->manager)
-			pr_cont(" manager: %d",
-				task_pid_nr(pool->manager->task));
-		list_for_each_entry(worker, &pool->idle_list, entry) {
-			pr_cont(" %s%d", first ? "idle: " : "",
-				task_pid_nr(worker->task));
-			first = false;
-		}
-		pr_cont("\n");
-	next_pool:
-		raw_spin_unlock_irqrestore(&pool->lock, flags);
+	for_each_pwq(pwq, wq) {
+		raw_spin_lock_irqsave(&pwq->pool->lock, flags);
+		if (pwq->nr_active || !list_empty(&pwq->inactive_works))
+			show_pwq(pwq);
+		raw_spin_unlock_irqrestore(&pwq->pool->lock, flags);
 		/*
 		 * We could be printing a lot from atomic context, e.g.
-		 * sysrq-t -> show_workqueue_state(). Avoid triggering
+		 * sysrq-t -> show_all_workqueues(). Avoid triggering
 		 * hard lockup.
 		 */
 		touch_nmi_watchdog();
 	}
 
+}
+
+/**
+ * show_one_worker_pool - dump state of specified worker pool
+ * @pool: worker pool whose state will be printed
+ */
+static void show_one_worker_pool(struct worker_pool *pool)
+{
+	struct worker *worker;
+	bool first = true;
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&pool->lock, flags);
+	if (pool->nr_workers == pool->nr_idle)
+		goto next_pool;
+
+	pr_info("pool %d:", pool->id);
+	pr_cont_pool_info(pool);
+	pr_cont(" hung=%us workers=%d",
+		jiffies_to_msecs(jiffies - pool->watchdog_ts) / 1000,
+		pool->nr_workers);
+	if (pool->manager)
+		pr_cont(" manager: %d",
+			task_pid_nr(pool->manager->task));
+	list_for_each_entry(worker, &pool->idle_list, entry) {
+		pr_cont(" %s%d", first ? "idle: " : "",
+			task_pid_nr(worker->task));
+		first = false;
+	}
+	pr_cont("\n");
+next_pool:
+	raw_spin_unlock_irqrestore(&pool->lock, flags);
+	/*
+	 * We could be printing a lot from atomic context, e.g.
+	 * sysrq-t -> show_all_workqueues(). Avoid triggering
+	 * hard lockup.
+	 */
+	touch_nmi_watchdog();
+
+}
+
+/**
+ * show_all_workqueues - dump workqueue state
+ *
+ * Called from a sysrq handler or try_to_freeze_tasks() and prints out
+ * all busy workqueues and pools.
+ */
+void show_all_workqueues(void)
+{
+	struct workqueue_struct *wq;
+	struct worker_pool *pool;
+	int pi;
+
+	rcu_read_lock();
+
+	pr_info("Showing busy workqueues and worker pools:\n");
+
+	list_for_each_entry_rcu(wq, &workqueues, list)
+		show_one_workqueue(wq);
+
+	for_each_pool(pool, pi)
+		show_one_worker_pool(pool);
+
 	rcu_read_unlock();
 }
 
@@ -5855,7 +5875,7 @@ static void wq_watchdog_timer_fn(struct timer_list *unused)
 	rcu_read_unlock();
 
 	if (lockup_detected)
-		show_workqueue_state();
+		show_all_workqueues();
 
 	wq_watchdog_reset_touched();
 	mod_timer(&wq_watchdog_timer, jiffies + thresh);

base-commit: 683f29b781aeaab6bf302eeb2ef08a5e5f9d8a27
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [RFC PATCH v3] workqueue: Introduce show_one_worker_pool and show_one_workqueue.
  2021-10-16  0:20 [RFC PATCH v3] workqueue: Introduce show_one_worker_pool and show_one_workqueue Imran Khan
@ 2021-10-19 18:41 ` Tejun Heo
  2021-10-20  8:27   ` Imran Khan
  0 siblings, 1 reply; 3+ messages in thread
From: Tejun Heo @ 2021-10-19 18:41 UTC (permalink / raw)
  To: Imran Khan
  Cc: jiangshanlai, gregkh, jirislaby, rafael, pavel, len.brown,
	linux-kernel, linux-pm

On Sat, Oct 16, 2021 at 11:20:07AM +1100, Imran Khan wrote:
> Currently show_workqueue_state shows the state of all workqueues and of
> all worker pools. In certain cases we may need to dump state of only a
> specific workqueue or worker pool. For example in destroy_workqueue we
> only need to show state of the workqueue which is getting destroyed.
> 
> So rename show_workqueue_state to show_all_workqueues(to signify it
> dumps state of all busy workqueues) and divide it into more granular
> functions (show_one_workqueue and show_one_worker_pool), that would show
> states of individual workqueues and worker pools and can be used in
> cases such as the one mentioned above.
> 
> Also, as mentioned earlier, make destroy_workqueue dump data pertaining
> to only the workqueue that is being destroyed and make user(s) of
> earlier interface(show_workqueue_state), use new interface
> (show_all_workqueues).
> 
> Signed-off-by: Imran Khan <imran.f.khan@oracle.com>

Can you respin the patch on top of the following branch?

 git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git for-5.16

Thank you.

-- 
tejun

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [RFC PATCH v3] workqueue: Introduce show_one_worker_pool and show_one_workqueue.
  2021-10-19 18:41 ` Tejun Heo
@ 2021-10-20  8:27   ` Imran Khan
  0 siblings, 0 replies; 3+ messages in thread
From: Imran Khan @ 2021-10-20  8:27 UTC (permalink / raw)
  To: Tejun Heo
  Cc: jiangshanlai, gregkh, jirislaby, rafael, pavel, len.brown,
	linux-kernel, linux-pm

Hi Tejun,

On 20/10/21 5:41 am, Tejun Heo wrote:
> On Sat, Oct 16, 2021 at 11:20:07AM +1100, Imran Khan wrote:
>> Currently show_workqueue_state shows the state of all workqueues and of
>> all worker pools. In certain cases we may need to dump state of only a
>> specific workqueue or worker pool. For example in destroy_workqueue we
>> only need to show state of the workqueue which is getting destroyed.
>>
>> So rename show_workqueue_state to show_all_workqueues(to signify it
>> dumps state of all busy workqueues) and divide it into more granular
>> functions (show_one_workqueue and show_one_worker_pool), that would show
>> states of individual workqueues and worker pools and can be used in
>> cases such as the one mentioned above.
>>
>> Also, as mentioned earlier, make destroy_workqueue dump data pertaining
>> to only the workqueue that is being destroyed and make user(s) of
>> earlier interface(show_workqueue_state), use new interface
>> (show_all_workqueues).
>>
>> Signed-off-by: Imran Khan <imran.f.khan@oracle.com>
> 
> Can you respin the patch on top of the following branch?
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git for-5.16

Sure, I have rebased it upon the suggested branch and have sent v4 [1] 
of the change.

[1] 
https://lore.kernel.org/lkml/20211020030900.321837-1-imran.f.khan@oracle.com/

Thanks,
--Imran
> 
> Thank you.
> 

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2021-10-20  8:27 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-16  0:20 [RFC PATCH v3] workqueue: Introduce show_one_worker_pool and show_one_workqueue Imran Khan
2021-10-19 18:41 ` Tejun Heo
2021-10-20  8:27   ` Imran Khan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).