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: Tejun Heo <tj@kernel.org> Reported-and-tested-by: Jan Engelhardt <jengelh@inai.de> Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
8f6a15f095
commit
2a1b02bcba
@ -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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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 @@ woke_up:
|
|||||||
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,
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
/* 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)
|
|||||||
}
|
}
|
||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user