Commit 2a1b02bc authored by Tejun Heo's avatar Tejun Heo

workqueue: Refactor worker ID formatting and make wq_worker_comm() use full ID string

Currently, worker ID formatting is open coded in create_worker(),
init_rescuer() and worker_thread() (for %WORKER_DIE case). The formatted ID
is saved into task->comm and wq_worker_comm() uses it as the base name to
append extra information to when generating the name to be shown to
userspace.

However, TASK_COMM_LEN is only 16 leading to badly truncated names for
rescuers. For example, the rescuer for the inet_frag_wq workqueue becomes:

  $ ps -ef | grep '[k]worker/R-inet'
  root         483       2  0 Apr26 ?        00:00:00 [kworker/R-inet_]

Even for non-rescue workers, it's easy to run over 15 characters on
moderately large machines.

Fit it by consolidating worker ID formatting into a new helper
format_worker_id() and calling it from wq_worker_comm() to obtain the
untruncated worker ID string.

  $ ps -ef | grep '[k]worker/R-inet'
  root          60       2  0 12:10 ?        00:00:00 [kworker/R-inet_frag_wq]
Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Reported-and-tested-by: default avatarJan Engelhardt <jengelh@inai.de>
Suggested-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 8f6a15f0
...@@ -125,6 +125,7 @@ enum wq_internal_consts { ...@@ -125,6 +125,7 @@ enum wq_internal_consts {
HIGHPRI_NICE_LEVEL = MIN_NICE, HIGHPRI_NICE_LEVEL = MIN_NICE,
WQ_NAME_LEN = 32, WQ_NAME_LEN = 32,
WORKER_ID_LEN = 10 + WQ_NAME_LEN, /* "kworker/R-" + WQ_NAME_LEN */
}; };
/* /*
...@@ -2742,6 +2743,26 @@ static void worker_detach_from_pool(struct worker *worker) ...@@ -2742,6 +2743,26 @@ static void worker_detach_from_pool(struct worker *worker)
complete(detach_completion); complete(detach_completion);
} }
static int format_worker_id(char *buf, size_t size, struct worker *worker,
struct worker_pool *pool)
{
if (worker->rescue_wq)
return scnprintf(buf, size, "kworker/R-%s",
worker->rescue_wq->name);
if (pool) {
if (pool->cpu >= 0)
return scnprintf(buf, size, "kworker/%d:%d%s",
pool->cpu, worker->id,
pool->attrs->nice < 0 ? "H" : "");
else
return scnprintf(buf, size, "kworker/u%d:%d",
pool->id, worker->id);
} else {
return scnprintf(buf, size, "kworker/dying");
}
}
/** /**
* create_worker - create a new workqueue worker * create_worker - create a new workqueue worker
* @pool: pool the new worker will belong to * @pool: pool the new worker will belong to
...@@ -2758,7 +2779,6 @@ static struct worker *create_worker(struct worker_pool *pool) ...@@ -2758,7 +2779,6 @@ static struct worker *create_worker(struct worker_pool *pool)
{ {
struct worker *worker; struct worker *worker;
int id; int id;
char id_buf[23];
/* ID is needed to determine kthread name */ /* ID is needed to determine kthread name */
id = ida_alloc(&pool->worker_ida, GFP_KERNEL); id = ida_alloc(&pool->worker_ida, GFP_KERNEL);
...@@ -2777,17 +2797,14 @@ static struct worker *create_worker(struct worker_pool *pool) ...@@ -2777,17 +2797,14 @@ static struct worker *create_worker(struct worker_pool *pool)
worker->id = id; worker->id = id;
if (!(pool->flags & POOL_BH)) { if (!(pool->flags & POOL_BH)) {
if (pool->cpu >= 0) char id_buf[WORKER_ID_LEN];
snprintf(id_buf, sizeof(id_buf), "%d:%d%s", pool->cpu, id,
pool->attrs->nice < 0 ? "H" : "");
else
snprintf(id_buf, sizeof(id_buf), "u%d:%d", pool->id, id);
format_worker_id(id_buf, sizeof(id_buf), worker, pool);
worker->task = kthread_create_on_node(worker_thread, worker, worker->task = kthread_create_on_node(worker_thread, worker,
pool->node, "kworker/%s", id_buf); pool->node, "%s", id_buf);
if (IS_ERR(worker->task)) { if (IS_ERR(worker->task)) {
if (PTR_ERR(worker->task) == -EINTR) { if (PTR_ERR(worker->task) == -EINTR) {
pr_err("workqueue: Interrupted when creating a worker thread \"kworker/%s\"\n", pr_err("workqueue: Interrupted when creating a worker thread \"%s\"\n",
id_buf); id_buf);
} else { } else {
pr_err_once("workqueue: Failed to create a worker thread: %pe", pr_err_once("workqueue: Failed to create a worker thread: %pe",
...@@ -3350,7 +3367,6 @@ static int worker_thread(void *__worker) ...@@ -3350,7 +3367,6 @@ static int worker_thread(void *__worker)
raw_spin_unlock_irq(&pool->lock); raw_spin_unlock_irq(&pool->lock);
set_pf_worker(false); set_pf_worker(false);
set_task_comm(worker->task, "kworker/dying");
ida_free(&pool->worker_ida, worker->id); ida_free(&pool->worker_ida, worker->id);
worker_detach_from_pool(worker); worker_detach_from_pool(worker);
WARN_ON_ONCE(!list_empty(&worker->entry)); WARN_ON_ONCE(!list_empty(&worker->entry));
...@@ -5542,6 +5558,7 @@ static int wq_clamp_max_active(int max_active, unsigned int flags, ...@@ -5542,6 +5558,7 @@ static int wq_clamp_max_active(int max_active, unsigned int flags,
static int init_rescuer(struct workqueue_struct *wq) static int init_rescuer(struct workqueue_struct *wq)
{ {
struct worker *rescuer; struct worker *rescuer;
char id_buf[WORKER_ID_LEN];
int ret; int ret;
if (!(wq->flags & WQ_MEM_RECLAIM)) if (!(wq->flags & WQ_MEM_RECLAIM))
...@@ -5555,7 +5572,9 @@ static int init_rescuer(struct workqueue_struct *wq) ...@@ -5555,7 +5572,9 @@ static int init_rescuer(struct workqueue_struct *wq)
} }
rescuer->rescue_wq = wq; rescuer->rescue_wq = wq;
rescuer->task = kthread_create(rescuer_thread, rescuer, "kworker/R-%s", wq->name); format_worker_id(id_buf, sizeof(id_buf), rescuer, NULL);
rescuer->task = kthread_create(rescuer_thread, rescuer, "%s", id_buf);
if (IS_ERR(rescuer->task)) { if (IS_ERR(rescuer->task)) {
ret = PTR_ERR(rescuer->task); ret = PTR_ERR(rescuer->task);
pr_err("workqueue: Failed to create a rescuer kthread for wq \"%s\": %pe", pr_err("workqueue: Failed to create a rescuer kthread for wq \"%s\": %pe",
...@@ -6384,19 +6403,15 @@ void show_freezable_workqueues(void) ...@@ -6384,19 +6403,15 @@ void show_freezable_workqueues(void)
/* used to show worker information through /proc/PID/{comm,stat,status} */ /* used to show worker information through /proc/PID/{comm,stat,status} */
void wq_worker_comm(char *buf, size_t size, struct task_struct *task) void wq_worker_comm(char *buf, size_t size, struct task_struct *task)
{ {
int off;
/* always show the actual comm */
off = strscpy(buf, task->comm, size);
if (off < 0)
return;
/* stabilize PF_WQ_WORKER and worker pool association */ /* stabilize PF_WQ_WORKER and worker pool association */
mutex_lock(&wq_pool_attach_mutex); mutex_lock(&wq_pool_attach_mutex);
if (task->flags & PF_WQ_WORKER) { if (task->flags & PF_WQ_WORKER) {
struct worker *worker = kthread_data(task); struct worker *worker = kthread_data(task);
struct worker_pool *pool = worker->pool; struct worker_pool *pool = worker->pool;
int off;
off = format_worker_id(buf, size, worker, pool);
if (pool) { if (pool) {
raw_spin_lock_irq(&pool->lock); raw_spin_lock_irq(&pool->lock);
...@@ -6415,6 +6430,8 @@ void wq_worker_comm(char *buf, size_t size, struct task_struct *task) ...@@ -6415,6 +6430,8 @@ void wq_worker_comm(char *buf, size_t size, struct task_struct *task)
} }
raw_spin_unlock_irq(&pool->lock); raw_spin_unlock_irq(&pool->lock);
} }
} else {
strscpy(buf, task->comm, size);
} }
mutex_unlock(&wq_pool_attach_mutex); mutex_unlock(&wq_pool_attach_mutex);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment