[RFC PATCH 1/5] fs/proc: Introduce /proc/all/stat

Eugene Lubarsky
2020-08-10T14:59:11Z

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@gmail.com>
---
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