[PATCH v6 4/6] sched: Extend task command name with TASK_COMM_EXT_LEN

From: André Almeida

Date: Thu Sep 10 2026 - 13:05:29 EST


Command name has been restrict to only 16 bytes, which is too limiting,
specially when debugging and tracing complex software with thousands of
threads and the need to differentiate them.

Just as it was done with kthreads in commit 6b59808bfe48 ("workqueue:
Show the latest workqueue name in /proc/PID/{comm,stat,status}"), support
long names for userspace threads as well.

To avoid buffer overflows, cap all existing userspace APIs to
TASK_COMM_LEN, and leave the full extended name for a new interface.

Signed-off-by: André Almeida <andrealmeid@xxxxxxxxxx>
---
Changes from v5:
- Fix blktrace buffer size
- Fix i915 buffer size
---
drivers/gpu/drm/i915/display/intel_display_driver.c | 4 ++--
drivers/gpu/drm/i915/gem/i915_gem_context.c | 4 ++--
fs/proc/array.c | 2 +-
include/linux/sched.h | 5 +++--
kernel/sys.c | 10 +++++-----
kernel/trace/blktrace.c | 6 ++++--
6 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c
index 70d112fd4287..e2b19b064722 100644
--- a/drivers/gpu/drm/i915/display/intel_display_driver.c
+++ b/drivers/gpu/drm/i915/display/intel_display_driver.c
@@ -435,8 +435,8 @@ void intel_display_driver_resume_access(struct intel_display *display)
*/
bool intel_display_driver_check_access(struct intel_display *display)
{
- char current_task[TASK_COMM_LEN + 16];
- char allowed_task[TASK_COMM_LEN + 16] = "none";
+ char current_task[TASK_COMM_EXT_LEN + 16];
+ char allowed_task[TASK_COMM_EXT_LEN + 16] = "none";

if (display->access.any_task_allowed ||
display->access.allowed_task == current)
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index c58ffa5a8fa6..b62b82c6de04 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -1730,8 +1730,8 @@ static void gem_context_register(struct i915_gem_context *ctx,
ctx->pid = get_task_pid(current, PIDTYPE_PID);
ctx->client = i915_drm_client_get(fpriv->client);

- snprintf(ctx->name, sizeof(ctx->name), "%s[%d]",
- current->comm, pid_nr(ctx->pid));
+ snprintf(ctx->name, sizeof(ctx->name), "%.*s[%d]",
+ TASK_COMM_LEN - 1, current->comm, pid_nr(ctx->pid));

spin_lock(&ctx->client->ctx_lock);
list_add_tail_rcu(&ctx->client_link, &ctx->client->ctx_list);
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 8ebb7cf1a7b0..0d70b21c803c 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -110,7 +110,7 @@ void proc_task_name(struct seq_file *m, struct task_struct *p, bool escape)
else if (p->flags & PF_KTHREAD)
get_kthread_comm(tcomm, sizeof(tcomm), p);
else
- strscpy_pad(tcomm, p->comm);
+ strscpy_pad(tcomm, p->comm, TASK_COMM_LEN);

if (escape)
seq_escape_str(m, tcomm, ESCAPE_SPACE | ESCAPE_SPECIAL, "\n\\");
diff --git a/include/linux/sched.h b/include/linux/sched.h
index ba2040566424..c4e0104e7ae9 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -323,6 +323,7 @@ struct user_event_mm;
*/
enum {
TASK_COMM_LEN = 16,
+ TASK_COMM_EXT_LEN = 64,
};

extern void sched_tick(void);
@@ -1187,7 +1188,7 @@ struct task_struct {
* - set it with set_task_comm() to ensure it is always
* NUL-terminated and zero-padded
*/
- char comm[TASK_COMM_LEN];
+ char comm[TASK_COMM_EXT_LEN];

struct nameidata *nameidata;

@@ -2042,7 +2043,7 @@ extern void __set_task_comm(struct task_struct *tsk, const char *from, bool exec
static __always_inline void copy_task_comm(char *dst, struct task_struct *tsk, size_t len)
{
const char *_src = tsk->comm;
- size_t _len = min(len, TASK_COMM_LEN);
+ size_t _len = min(len, TASK_COMM_EXT_LEN);

if (!_len)
return;
diff --git a/kernel/sys.c b/kernel/sys.c
index 97df708c11a0..5ebd3c1dfddf 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -2535,7 +2535,7 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
unsigned long, arg4, unsigned long, arg5)
{
struct task_struct *me = current;
- unsigned char comm[sizeof(me->comm)];
+ unsigned char comm[TASK_COMM_LEN];
long error;

error = security_task_prctl(option, arg2, arg3, arg4, arg5);
@@ -2601,16 +2601,16 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
error = -EINVAL;
break;
case PR_SET_NAME:
- comm[sizeof(me->comm) - 1] = 0;
+ comm[TASK_COMM_LEN - 1] = 0;
if (strncpy_from_user(comm, (char __user *)arg2,
- sizeof(me->comm) - 1) < 0)
+ TASK_COMM_LEN - 1) < 0)
return -EFAULT;
set_task_comm(me, comm);
proc_comm_connector(me);
break;
case PR_GET_NAME:
- strscpy_pad(comm, me->comm);
- if (copy_to_user((char __user *)arg2, comm, sizeof(comm)))
+ strscpy_pad(comm, me->comm, TASK_COMM_LEN);
+ if (copy_to_user((char __user *)arg2, comm, TASK_COMM_LEN))
return -EFAULT;
break;
case PR_GET_ENDIAN:
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index 8cd2520b4c99..edc1377c3e3c 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -214,12 +214,14 @@ static void trace_note_tsk(struct task_struct *tsk)
{
unsigned long flags;
struct blk_trace *bt;
+ char comm[TASK_COMM_LEN];

tsk->btrace_seq = blktrace_seq;
raw_spin_lock_irqsave(&running_trace_lock, flags);
list_for_each_entry(bt, &running_trace_list, running_list) {
- trace_note(bt, tsk->pid, BLK_TN_PROCESS, tsk->comm,
- sizeof(tsk->comm), 0);
+ strscpy_pad(comm, tsk->comm);
+ trace_note(bt, tsk->pid, BLK_TN_PROCESS, comm,
+ sizeof(comm), 0);
}
raw_spin_unlock_irqrestore(&running_trace_lock, flags);
}

--
2.55.0