Returns stat lines for all visible processes in the existing format, aiming to substantially reduce the number of syscalls that are needed for this common task. Signed-off-by: Eugene Lubarsky <elubarsky.linux@xxxxxxxxx> --- fs/proc/base.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++ fs/proc/internal.h | 1 + fs/proc/root.c | 1 + 3 files changed, 100 insertions(+) diff --git a/fs/proc/base.c b/fs/proc/base.c index a333caeca291..e0f60a1528b7 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -3811,3 +3811,101 @@ void __init set_proc_pid_nlink(void) nlink_tid = pid_entry_nlink(tid_base_stuff, ARRAY_SIZE(tid_base_stuff)); nlink_tgid = pid_entry_nlink(tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff)); } + + +/* + * /proc/all/ + */ + +struct all_iter { + struct tgid_iter tgid_iter; + struct proc_fs_info *fs_info; + struct pid_namespace *ns; +}; + +static void *proc_all_start(struct seq_file *m, loff_t *pos) +{ + struct all_iter *iter = kmalloc(sizeof(struct all_iter), GFP_KERNEL); + + iter->fs_info = proc_sb_info(file_inode(m->file)->i_sb); + iter->ns = proc_pid_ns(file_inode(m->file)->i_sb); + + iter->tgid_iter.tgid = *pos; + iter->tgid_iter.task = NULL; + iter->tgid_iter = next_tgid(iter->ns, iter->tgid_iter); + + if (!iter->tgid_iter.task) { + kfree(iter); + return NULL; + } + + return iter; +} + +static void *proc_all_next(struct seq_file *m, void *v, loff_t *pos) +{ + struct all_iter *iter = (struct all_iter *) v; + struct proc_fs_info *fs_info = iter->fs_info; + struct tgid_iter *tgid_iter = &iter->tgid_iter; + + do { + tgid_iter->tgid += 1; + *tgid_iter = next_tgid(iter->ns, *tgid_iter); + } while (tgid_iter->task && + !has_pid_permissions(fs_info, tgid_iter->task, HIDEPID_INVISIBLE)); + + *pos = tgid_iter->tgid; + + if (!tgid_iter->task) { + kfree(v); + return NULL; + } + + return iter; +} + +static void proc_all_stop(struct seq_file *m, void *v) +{ + if (v) { + struct all_iter *iter = (struct all_iter *) v; + struct task_struct *task = iter->tgid_iter.task; + + if (task) + put_task_struct(task); + + kfree(v); + } +} + +static int proc_all_stat(struct seq_file *m, void *v) +{ + struct all_iter *iter = (struct all_iter *) v; + + return proc_tgid_stat(m, iter->ns, iter->tgid_iter.task->thread_pid, iter->tgid_iter.task); +} + + +#define PROC_ALL_OPS(NAME) static const struct seq_operations proc_all_##NAME##_ops = { \ + .start = proc_all_start, \ + .next = proc_all_next, \ + .stop = proc_all_stop, \ + .show = proc_all_##NAME \ +} + +PROC_ALL_OPS(stat); + +#define PROC_ALL_CREATE(NAME) \ + do { \ + if (!proc_create_seq(#NAME, 0, all_dir, &proc_all_##NAME##_ops)) \ + return; \ + } while (0) + +void __init proc_all_init(void) +{ + struct proc_dir_entry *all_dir = proc_mkdir("all", NULL); + + if (!all_dir) + return; + + PROC_ALL_CREATE(stat); +} diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 917cc85e3466..b22d9cb619bf 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -171,6 +171,7 @@ extern int pid_delete_dentry(const struct dentry *); extern int proc_pid_readdir(struct file *, struct dir_context *); struct dentry *proc_pid_lookup(struct dentry *, unsigned int); extern loff_t mem_lseek(struct file *, loff_t, int); +extern void proc_all_init(void); /* Lookups */ typedef struct dentry *instantiate_t(struct dentry *, diff --git a/fs/proc/root.c b/fs/proc/root.c index 5e444d4f9717..4b5cfd2cdc0a 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -291,6 +291,7 @@ void __init proc_root_init(void) set_proc_pid_nlink(); proc_self_init(); proc_thread_self_init(); + proc_all_init(); proc_symlink("mounts", NULL, "self/mounts"); proc_net_init(); -- 2.25.1