Subject: [PATCH] pspace: Update /proc so pspaces are easily visible. From: Eric W. Biederman Date: 1134518943 -0700 Currently under /proc//pspace is another copy of proc. However this has the bad side effect that ps and top don't know anything about your pspace. This patch adds stat, statm, status, and cmdline under /proc/ allowing ps and proc to find the pspace. Most fields are not filled out. Those that are generally apply to the whole pspace, except for the process name which only applies to the init process of the pspace. --- fs/proc/array.c | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/proc/base.c | 26 +++++++ fs/proc/internal.h | 3 + 3 files changed, 219 insertions(+), 2 deletions(-) 310b7bae1801014b19be2f4b2a075c24a3775247 diff --git a/fs/proc/array.c b/fs/proc/array.c index 64cc859..dea5bff 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -75,6 +75,7 @@ #include #include #include +#include #include #include @@ -137,6 +138,8 @@ static const char *task_state_array[] = "Z (zombie)", /* 16 */ "X (dead)" /* 32 */ }; +static const char task_state_pspace[] = + "P (pspace)"; static inline const char * get_task_state(struct task_struct *tsk) { @@ -206,6 +209,47 @@ static inline char * task_state(struct t return buffer; } + +static inline char * pspace_task_state(struct task_struct *p, char *buffer) +{ + struct group_info *group_info; + int g; + + read_lock(&tasklist_lock); + buffer += sprintf(buffer, + "State:\t%s\n" + "Tgid:\t%d\n" + "Pid:\t%d\n" + "PPid:\t%d\n" + "TracerPid:\t%d\n" + "Uid:\t%d\t%d\t%d\t%d\n" + "Gid:\t%d\t%d\t%d\t%d\n", + task_state_pspace, + p->wid, + p->wid, + task_alive(p)? p->group_leader->real_parent->tgid : 0, + task_alive(p) && p->ptrace ? p->parent->tid : 0, + p->uid, p->euid, p->suid, p->fsuid, + p->gid, p->egid, p->sgid, p->fsgid); + read_unlock(&tasklist_lock); + task_lock(p); + rcu_read_lock(); + buffer += sprintf(buffer, + "Groups:\t"); + rcu_read_unlock(); + + group_info = p->group_info; + get_group_info(group_info); + task_unlock(p); + + for (g = 0; g < min(group_info->ngroups,NGROUPS_SMALL); g++) + buffer += sprintf(buffer, "%d ", GROUP_AT(group_info,g)); + put_group_info(group_info); + + buffer += sprintf(buffer, "\n"); + return buffer; +} + static char * render_sigset_t(const char *header, sigset_t *set, char *buffer) { int i, len; @@ -318,6 +362,15 @@ int proc_pid_status(struct task_struct * return buffer - orig; } +int proc_pspace_status(struct task_struct *task, char * buffer) +{ + char *orig = buffer; + buffer = task_name(task, buffer); + buffer = pspace_task_state(task, buffer); + buffer += sprintf(buffer, "Threads:\t%d\n", task->pspace->nr_threads); + return buffer - orig; +} + static int do_task_stat(struct task_struct *task, char * buffer, int whole) { unsigned long vsize, eip, esp, wchan = ~0UL; @@ -481,6 +534,137 @@ int proc_tgid_stat(struct task_struct *t return do_task_stat(task, buffer, 1); } +int proc_pspace_stat(struct task_struct *task, char * buffer) +{ + struct pspace *pspace = task->pspace; + long priority, nice; + int tty_pgrp = -1, tty_nr = 0; + char state; + int res; + pid_t ppid, pgid = -1, sid = -1; + int num_threads = 0; + unsigned long long start_time; + unsigned long cmin_flt = 0, cmaj_flt = 0; + unsigned long min_flt = 0, maj_flt = 0; + cputime_t cutime, cstime, utime, stime; + struct task_struct *p; + char tcomm[sizeof(task->comm)]; + + state = *task_state_pspace; + get_task_comm(tcomm, task); + + cutime = cstime = utime = stime = cputime_zero; + + /* scale priority and nice values from timeslices to -20..20 */ + /* to make it look like a "normal" Unix priority/nice value */ + priority = task_prio(task); + nice = task_nice(task); + + /* add up live thread stats at the pspace level */ + read_lock(&tasklist_lock); + for_each_process(p) { + long t_priority, t_nice; + /* Skip processes outside the target process space */ + if (!in_pspace(pspace, p)) + continue; + + t_priority = task_prio(task); + t_nice = task_nice(task); + + if (priority > t_priority) + priority = t_priority; + if (nice > t_nice) + nice = t_nice; + + if (p->sighand) { + spin_lock_irq(&task->sighand->siglock); + min_flt += p->min_flt; + maj_flt += p->maj_flt; + utime = cputime_add(utime, p->utime); + stime = cputime_add(stime, p->stime); + spin_unlock_irq(&task->sighand->siglock); + } + if (thread_group_leader(p) && p->signal) { + min_flt += p->signal->min_flt; + maj_flt += p->signal->maj_flt; + utime = cputime_add(utime, p->signal->utime); + stime = cputime_add(stime, p->signal->stime); + cmin_flt += p->signal->cmin_flt; + cmaj_flt += p->signal->cmaj_flt; + cutime += p->signal->cutime; + cstime += p->signal->cstime; + } + if (pspace_leader(p)) { + num_threads += p->pspace->nr_threads; + } + } + if (task->signal) { + if (task->signal->tty) { + tty_pgrp = task->wid; + tty_nr = new_encode_dev(tty_devnum(task->signal->tty)); + } + } + ppid = task_alive(task)? task->group_leader->real_parent->tgid : 0; + read_unlock(&tasklist_lock); + + /* Temporary variable needed for gcc-2.96 */ + /* convert timespec -> nsec*/ + start_time = (unsigned long long)task->start_time.tv_sec * NSEC_PER_SEC + + task->start_time.tv_nsec; + /* convert nsec -> ticks */ + start_time = nsec_to_clock_t(start_time); + + res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ +%lu %lu %lu %lu %lu %ld %ld %ld %ld %d %ld %llu %lu %ld %lu %lu %lu %lu %lu \ +%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu\n", + task->wid, + tcomm, + state, + ppid, + pgid, + sid, + tty_nr, + tty_pgrp, + 0UL, /* task->flags */ + min_flt, + cmin_flt, + maj_flt, + cmaj_flt, + cputime_to_clock_t(utime), + cputime_to_clock_t(stime), + cputime_to_clock_t(cutime), + cputime_to_clock_t(cstime), + priority, + nice, + num_threads, + 0UL /* it_real_value (Not implemented) */, + start_time, + 0UL /* vsize */, + 0L /* mm_counter */, + 0UL /* rsslim */, + 0UL /* start_code */, + 0UL /* end_code */, + 0UL /* start_stack */, + 0UL /* esp */, + 0UL /* eip */, + /* The signal information here is obsolete. + * It must be decimal for Linux 2.0 compatibility. + * Use /proc/#/status for real-time signals. + */ + 0UL /* task->pending.signal.sig[0] & 0x7fffffffUL */, + 0UL /* task->blocked.sig[0] & 0x7fffffffUL */, + 0UL /* sigign .sig[0] & 0x7fffffffUL */, + 0UL /* sigcatch .sig[0] & 0x7fffffffUL */, + 0UL /* wchan */, + 0UL, + 0UL, + task->exit_signal, + 0 /* task_cpu(task) */, + 0UL /* task->rt_priority*/, + 0UL /* task->policy*/); + return res; +} + int proc_pid_statm(struct task_struct *task, char *buffer) { int size = 0, resident = 0, shared = 0, text = 0, lib = 0, data = 0; @@ -494,3 +678,11 @@ int proc_pid_statm(struct task_struct *t return sprintf(buffer,"%d %d %d %d %d %d %d\n", size, resident, shared, text, lib, data, 0); } + +int proc_pspace_statm(struct task_struct *task, char *buffer) +{ + int size = 0, resident = 0, shared = 0, text = 0, lib = 0, data = 0; + + return sprintf(buffer,"%d %d %d %d %d %d %d\n", + size, resident, shared, text, lib, data, 0); +} diff --git a/fs/proc/base.c b/fs/proc/base.c index 007bed3..9d0ea33 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -181,6 +181,11 @@ enum pid_directory_inos { PROC_TID_OOM_SCORE, PROC_TID_OOM_ADJUST, + PROC_PSPACE_STAT, + PROC_PSPACE_STATM, + PROC_PSPACE_STATUS, + PROC_PSPACE_CMDLINE, + #ifdef CONFIG_SYSVIPC PROC_SYSVIPC_MSG, PROC_SYSVIPC_SEM, @@ -298,7 +303,11 @@ static struct pid_entry tid_base_stuff[] }; static struct pid_entry pspace_base_stuff[] = { - E(PROC_ROOT_INO, "pspace", S_IFDIR|S_IRUGO|S_IXUGO), + E(PROC_ROOT_INO, "pspace", S_IFDIR|S_IRUGO|S_IXUGO), + E(PROC_PSPACE_STAT, "stat", S_IFREG|S_IRUGO), + E(PROC_PSPACE_STATM, "statm", S_IFREG|S_IRUGO), + E(PROC_PSPACE_STATUS, "status", S_IFREG|S_IRUGO), + E(PROC_PSPACE_CMDLINE, "cmdline", S_IFREG|S_IRUGO), {0,0,NULL,0} }; @@ -1959,6 +1968,10 @@ static struct dentry *proc_pident_lookup inode->i_fop = &proc_info_file_operations; ei->op.proc_read = proc_pid_status; break; + case PROC_PSPACE_STATUS: + inode->i_fop = &proc_info_file_operations; + ei->op.proc_read = proc_pspace_status; + break; case PROC_TID_STAT: inode->i_fop = &proc_info_file_operations; ei->op.proc_read = proc_tid_stat; @@ -1967,8 +1980,13 @@ static struct dentry *proc_pident_lookup inode->i_fop = &proc_info_file_operations; ei->op.proc_read = proc_tgid_stat; break; + case PROC_PSPACE_STAT: + inode->i_fop = &proc_info_file_operations; + ei->op.proc_read = proc_pspace_stat; + break; case PROC_TID_CMDLINE: case PROC_TGID_CMDLINE: + case PROC_PSPACE_CMDLINE: inode->i_fop = &proc_info_file_operations; ei->op.proc_read = proc_pid_cmdline; break; @@ -1977,6 +1995,10 @@ static struct dentry *proc_pident_lookup inode->i_fop = &proc_info_file_operations; ei->op.proc_read = proc_pid_statm; break; + case PROC_PSPACE_STATM: + inode->i_fop = &proc_info_file_operations; + ei->op.proc_read = proc_pspace_statm; + break; case PROC_TID_MAPS: case PROC_TGID_MAPS: inode->i_fop = &proc_maps_operations; @@ -2114,7 +2136,7 @@ static struct dentry *proc_pspace_base_l d_add(dentry, inode); return NULL; out: - return ERR_PTR(error); + return proc_pident_lookup(dir, dentry, pspace_base_stuff); } static struct file_operations proc_tgid_base_operations = { diff --git a/fs/proc/internal.h b/fs/proc/internal.h index c1ec992..ee1954c 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -34,8 +34,11 @@ extern void create_seq_entry(char *name, extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **); extern int proc_tid_stat(struct task_struct *, char *); extern int proc_tgid_stat(struct task_struct *, char *); +extern int proc_pspace_stat(struct task_struct *, char *); extern int proc_pid_status(struct task_struct *, char *); +extern int proc_pspace_status(struct task_struct *, char *); extern int proc_pid_statm(struct task_struct *, char *); +extern int proc_pspace_statm(struct task_struct *, char *); static inline struct task_struct *proc_task(struct inode *inode) { -- 1.0.GIT