--- include/linux/sched.h | 2 + include/linux/workqueue.h | 3 +- kernel/trace/latency_hist.c | 16 +++++++++--- kernel/workqueue.c | 55 ++++++++++++++++++++++++++++++++------------ 4 files changed, 57 insertions(+), 19 deletions(-) Index: linux-5.15.71-rt51-r3s4/include/linux/sched.h =================================================================== @ linux-5.15.71-rt51-r3s4/include/linux/sched.h:71 @ struct signal_struct; struct task_delay_info; struct task_group; +#define MAXFULLTASKNAME 64 + /* * Task state bitmask. NOTE! These bits are also * encoded in fs/proc/array.c: get_task_state(). Index: linux-5.15.71-rt51-r3s4/include/linux/workqueue.h =================================================================== --- linux-5.15.71-rt51-r3s4.orig/include/linux/workqueue.h +++ linux-5.15.71-rt51-r3s4/include/linux/workqueue.h @ linux-5.15.71-rt51-r3s4/include/linux/sched.h:94 @ enum { WORK_BUSY_RUNNING = 1 << 1, /* maximum string length for set_worker_desc() */ - WORKER_DESC_LEN = 24, + WORKER_DESC_LEN = 48, }; struct work_struct { @ linux-5.15.71-rt51-r3s4/include/linux/sched.h:474 @ extern __printf(1, 2) void set_worker_de extern void print_worker_info(const char *log_lvl, struct task_struct *task); extern void show_workqueue_state(void); extern void wq_worker_comm(char *buf, size_t size, struct task_struct *task); +extern void wq_worker_comm_nolock(char *buf, size_t size, struct task_struct *task); /** * queue_work - queue work on a workqueue Index: linux-5.15.71-rt51-r3s4/kernel/trace/latency_hist.c =================================================================== --- linux-5.15.71-rt51-r3s4.orig/kernel/trace/latency_hist.c +++ linux-5.15.71-rt51-r3s4/kernel/trace/latency_hist.c @ linux-5.15.71-rt51-r3s4/include/linux/sched.h:116 @ static struct enable_data preemptirqsoff defined(CONFIG_MISSED_TIMER_OFFSETS_HIST) struct maxlatproc_data { char comm[FIELD_SIZEOF(struct task_struct, comm)]; - char current_comm[FIELD_SIZEOF(struct task_struct, comm)]; + char current_comm[MAXFULLTASKNAME]; int pid; int current_pid; int prio; @ linux-5.15.71-rt51-r3s4/include/linux/sched.h:202 @ static struct enable_data timerwakeupswi static DEFINE_PER_CPU(struct maxlatproc_data, timerwakeupswitch_maxlatproc); #endif +static void fulltaskname(struct task_struct *p, char *tcomm, int size) +{ + if (p->flags & PF_WQ_WORKER) + wq_worker_comm_nolock(tcomm, size, p); + else + strscpy_pad(tcomm, p->comm, size); +} + void notrace latency_hist(int latency_type, int cpu, long latency, unsigned long timer_offset, long wakeup_latency, u64 stop, struct task_struct *p, int nr) @ linux-5.15.71-rt51-r3s4/include/linux/sched.h:309 @ void notrace latency_hist(int latency_ty latency_type == TIMERWAKEUPSWITCH_LATENCY) { if (latency_type == SWITCHTIME || latency_type == TIMERWAKEUPSWITCH_LATENCY) { - strncpy(mp->current_comm, p->comm, + fulltaskname(p, mp->current_comm, sizeof(mp->current_comm)); strncpy(mp->comm, current->comm, sizeof(mp->comm)); @ linux-5.15.71-rt51-r3s4/include/linux/sched.h:319 @ void notrace latency_hist(int latency_ty mp->prio = current->prio; } else { strncpy(mp->comm, p->comm, sizeof(mp->comm)); - strncpy(mp->current_comm, current->comm, + fulltaskname(current, mp->current_comm, sizeof(mp->current_comm)); mp->pid = task_pid_nr(p); mp->current_pid = task_pid_nr(current); @ linux-5.15.71-rt51-r3s4/include/linux/sched.h:604 @ show_maxlatproc(struct file *file, char { int r; struct maxlatproc_data *mp = file->private_data; - int strmaxlen = (TASK_COMM_LEN * 2) + 32 + (8 * 8); + int strmaxlen = 256; unsigned long long t; unsigned long usecs, secs; char *buf; Index: linux-5.15.71-rt51-r3s4/kernel/workqueue.c =================================================================== --- linux-5.15.71-rt51-r3s4.orig/kernel/workqueue.c +++ linux-5.15.71-rt51-r3s4/kernel/workqueue.c @ linux-5.15.71-rt51-r3s4/include/linux/sched.h:109 @ enum { RESCUER_NICE_LEVEL = MIN_NICE, HIGHPRI_NICE_LEVEL = MIN_NICE, - WQ_NAME_LEN = 24, + WQ_NAME_LEN = 48, }; /* @ linux-5.15.71-rt51-r3s4/include/linux/sched.h:4901 @ void show_workqueue_state(void) rcu_read_unlock(); } +static void wq_worker_print(char *buf, size_t size, int off, struct worker *worker) +{ + /* + * ->desc tracks information (wq name or + * set_worker_desc()) for the latest execution. If + * current, prepend '+' and show function, otherwise '-'. + */ + if (worker->desc[0] != '\0') { + if (worker->current_work) + scnprintf(buf + off, size - off, + "+%s@%ps", worker->desc, + worker->current_func); + else + scnprintf(buf + off, size - off, "-%s", + worker->desc); + } +} + /* used to show worker information through /proc/PID/{comm,stat,status} */ void wq_worker_comm(char *buf, size_t size, struct task_struct *task) { @ linux-5.15.71-rt51-r3s4/include/linux/sched.h:4929 @ void wq_worker_comm(char *buf, size_t si if (off < 0) return; +#ifndef CONFIG_PREEMPT_RT /* stabilize PF_WQ_WORKER and worker pool association */ mutex_lock(&wq_pool_attach_mutex); @ linux-5.15.71-rt51-r3s4/include/linux/sched.h:4939 @ void wq_worker_comm(char *buf, size_t si if (pool) { raw_spin_lock_irq(&pool->lock); - /* - * ->desc tracks information (wq name or - * set_worker_desc()) for the latest execution. If - * current, prepend '+', otherwise '-'. - */ - if (worker->desc[0] != '\0') { - if (worker->current_work) - scnprintf(buf + off, size - off, "+%s", - worker->desc); - else - scnprintf(buf + off, size - off, "-%s", - worker->desc); - } + wq_worker_print(buf, size, off, worker); raw_spin_unlock_irq(&pool->lock); } } mutex_unlock(&wq_pool_attach_mutex); +#endif +} + +/* used to get worker information for latency histograms */ +void wq_worker_comm_nolock(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; + + if (task->flags & PF_WQ_WORKER) { + struct worker *worker = kthread_data(task); + struct worker_pool *pool = worker->pool; + + if (pool) + wq_worker_print(buf, size, off, worker); + } } #ifdef CONFIG_SMP