procfs: allow threads to rename siblings via /proc/pid/tasks/tid/comm
Setting a thread's comm to be something unique is a very useful ability and is helpful for debugging complicated threaded applications. However currently the only way to set a thread name is for the thread to name itself via the PR_SET_NAME prctl. However, there may be situations where it would be advantageous for a thread dispatcher to be naming the threads its managing, rather then having the threads self-describe themselves. This sort of behavior is available on other systems via the pthread_setname_np() interface. This patch exports a task's comm via proc/pid/comm and proc/pid/task/tid/comm interfaces, and allows thread siblings to write to these values. [akpm@linux-foundation.org: cleanups] Signed-off-by: John Stultz <johnstul@us.ibm.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: Arjan van de Ven <arjan@infradead.org> Cc: Mike Fulton <fultonm@ca.ibm.com> Cc: Sean Foley <Sean_Foley@ca.ibm.com> Cc: Darren Hart <dvhltc@us.ibm.com> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
7e1e0ef22c
commit
4614a696bd
|
@ -38,6 +38,7 @@ Table of Contents
|
|||
3.3 /proc/<pid>/io - Display the IO accounting fields
|
||||
3.4 /proc/<pid>/coredump_filter - Core dump filtering settings
|
||||
3.5 /proc/<pid>/mountinfo - Information about mounts
|
||||
3.6 /proc/<pid>/comm & /proc/<pid>/task/<tid>/comm
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
|
@ -1409,3 +1410,11 @@ For more information on mount propagation see:
|
|||
|
||||
Documentation/filesystems/sharedsubtree.txt
|
||||
|
||||
|
||||
3.6 /proc/<pid>/comm & /proc/<pid>/task/<tid>/comm
|
||||
--------------------------------------------------------
|
||||
These files provide a method to access a tasks comm value. It also allows for
|
||||
a task to set its own or one of its thread siblings comm value. The comm value
|
||||
is limited in size compared to the cmdline value, so writing anything longer
|
||||
then the kernel's TASK_COMM_LEN (currently 16 chars) will result in a truncated
|
||||
comm value.
|
||||
|
|
|
@ -923,6 +923,15 @@ char *get_task_comm(char *buf, struct task_struct *tsk)
|
|||
void set_task_comm(struct task_struct *tsk, char *buf)
|
||||
{
|
||||
task_lock(tsk);
|
||||
|
||||
/*
|
||||
* Threads may access current->comm without holding
|
||||
* the task lock, so write the string carefully.
|
||||
* Readers without a lock may see incomplete new
|
||||
* names but are safe from non-terminating string reads.
|
||||
*/
|
||||
memset(tsk->comm, 0, TASK_COMM_LEN);
|
||||
wmb();
|
||||
strlcpy(tsk->comm, buf, sizeof(tsk->comm));
|
||||
task_unlock(tsk);
|
||||
perf_event_comm(tsk);
|
||||
|
|
|
@ -1265,6 +1265,72 @@ static const struct file_operations proc_pid_sched_operations = {
|
|||
|
||||
#endif
|
||||
|
||||
static ssize_t comm_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *offset)
|
||||
{
|
||||
struct inode *inode = file->f_path.dentry->d_inode;
|
||||
struct task_struct *p;
|
||||
char buffer[TASK_COMM_LEN];
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
if (count > sizeof(buffer) - 1)
|
||||
count = sizeof(buffer) - 1;
|
||||
if (copy_from_user(buffer, buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
p = get_proc_task(inode);
|
||||
if (!p)
|
||||
return -ESRCH;
|
||||
|
||||
if (same_thread_group(current, p))
|
||||
set_task_comm(p, buffer);
|
||||
else
|
||||
count = -EINVAL;
|
||||
|
||||
put_task_struct(p);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int comm_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct inode *inode = m->private;
|
||||
struct task_struct *p;
|
||||
|
||||
p = get_proc_task(inode);
|
||||
if (!p)
|
||||
return -ESRCH;
|
||||
|
||||
task_lock(p);
|
||||
seq_printf(m, "%s\n", p->comm);
|
||||
task_unlock(p);
|
||||
|
||||
put_task_struct(p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int comm_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = single_open(filp, comm_show, NULL);
|
||||
if (!ret) {
|
||||
struct seq_file *m = filp->private_data;
|
||||
|
||||
m->private = inode;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations proc_pid_set_comm_operations = {
|
||||
.open = comm_open,
|
||||
.read = seq_read,
|
||||
.write = comm_write,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
/*
|
||||
* We added or removed a vma mapping the executable. The vmas are only mapped
|
||||
* during exec and are not mapped with the mmap system call.
|
||||
|
@ -2504,6 +2570,7 @@ static const struct pid_entry tgid_base_stuff[] = {
|
|||
#ifdef CONFIG_SCHED_DEBUG
|
||||
REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations),
|
||||
#endif
|
||||
REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations),
|
||||
#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
|
||||
INF("syscall", S_IRUSR, proc_pid_syscall),
|
||||
#endif
|
||||
|
@ -2838,6 +2905,7 @@ static const struct pid_entry tid_base_stuff[] = {
|
|||
#ifdef CONFIG_SCHED_DEBUG
|
||||
REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations),
|
||||
#endif
|
||||
REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations),
|
||||
#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
|
||||
INF("syscall", S_IRUSR, proc_pid_syscall),
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue