[RFC PATCH 2/3] procfs: show hierarchy of pid namespace

From: Chen Hanxiao
Date: Wed Sep 03 2014 - 06:29:59 EST


This patch will show the hierarchy of pid namespace
under /proc/pidns like:
/proc/pidns
âââ hierarchy
â âââ pidns4026532399
â â âââ pidns -> /proc/2863/ns/pid
â â âââ pidns4026532515
â â âââ pidns -> /proc/10611/ns/pid
â âââ pidns4026532504
â âââ pidns -> /proc/4450/ns/pid
âââ refresh

a) hierarchy dir:
use to show hierarchy infomation using dir and symlinks.
dirs are named as pidns($inum)
a symlink is created under pidns($inum), and linked to
that pid namespace.

b) refresh
trigger key.
We need to write sth to /proc/nspid/refresh,
then we could get hierarchy info
under /proc/pidns/hierarchy.

Signed-off-by: Chen Hanxiao <chenhanxiao@xxxxxxxxxxxxxx>
---
fs/proc/Kconfig | 6 ++
fs/proc/Makefile | 1 +
fs/proc/pidns_hierarchy.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 168 insertions(+)
create mode 100644 fs/proc/pidns_hierarchy.c

diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig
index 2183fcf..e2e2292 100644
--- a/fs/proc/Kconfig
+++ b/fs/proc/Kconfig
@@ -71,3 +71,9 @@ config PROC_PAGE_MONITOR
/proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap,
/proc/kpagecount, and /proc/kpageflags. Disabling these
interfaces will reduce the size of the kernel by approximately 4kb.
+
+config PROC_PID_HIERARCHY
+ bool "Enable /proc/pidns_hierarchy support" if EXPERT
+ depends on PROC_FS
+ help
+ Show pid namespace hierarchy infomation
diff --git a/fs/proc/Makefile b/fs/proc/Makefile
index 239493e..733599b 100644
--- a/fs/proc/Makefile
+++ b/fs/proc/Makefile
@@ -29,3 +29,4 @@ proc-$(CONFIG_PROC_KCORE) += kcore.o
proc-$(CONFIG_PROC_VMCORE) += vmcore.o
proc-$(CONFIG_PRINTK) += kmsg.o
proc-$(CONFIG_PROC_PAGE_MONITOR) += page.o
+proc-$(CONFIG_PROC_PID_HIERARCHY) += pidns_hierarchy.o
diff --git a/fs/proc/pidns_hierarchy.c b/fs/proc/pidns_hierarchy.c
new file mode 100644
index 0000000..d35340f
--- /dev/null
+++ b/fs/proc/pidns_hierarchy.c
@@ -0,0 +1,161 @@
+/*
+ * proc_pidns_hierarchy.c -- handles pidns hierarchy
+ *
+ * Copyright 2014
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/pid_namespace.h>
+
+/*
+ * The /proc/pidns directory
+ */
+
+#define BASE_DIR "pidns" /* Subdir in /proc */
+#define HIERARCHY_DIR "pidns/hierarchy" /* hierarchy dir */
+#define REFRESH_KEY "pidns/refresh" /* refresh key */
+#define NAME "pidns_hierarchy" /* Module name */
+
+static LIST_HEAD(pidns_list);
+static DEFINE_RWLOCK(pidns_lock);
+static struct proc_dir_entry *proc_root;
+
+struct ns_pid_list {
+ struct pid *pid;
+ struct list_head list;
+};
+
+static void free_pidns_list(struct list_head *head)
+{
+ struct ns_pid_list *tmp, *pos;
+
+ list_for_each_entry_safe(pos, tmp, head, list) {
+ list_del(&pos->list);
+ kfree(pos);
+ }
+}
+
+/*
+ * Only add pids with different ns
+ */
+static int
+ns_pid_list_really_add(struct pid *pid)
+{
+ struct ns_pid_list *tmp, *pos;
+
+ list_for_each_entry_safe(pos, tmp, &pidns_list, list)
+ if (ns_of_pid(pid) == ns_of_pid(pos->pid))
+ return 0;
+
+ return 1;
+}
+
+static int
+ns_pid_list_add(struct pid *pid)
+{
+ struct ns_pid_list *ent;
+
+ ent = kmalloc(sizeof(*ent), GFP_KERNEL);
+ if (!ent)
+ return -ENOMEM;
+ ent->pid = pid;
+ if (ns_pid_list_really_add(pid))
+ list_add_tail(&ent->list, &pidns_list);
+
+ return 0;
+}
+
+static void print_list(void)
+{
+ struct ns_pid_list *tmp, *pos;
+ struct proc_dir_entry *parent, *parent_new;
+ struct pid_namespace *ns, *curr_ns;
+ struct pid *pid;
+ char name_buf[16], pid_buf[32];
+ int i, k;
+
+ curr_ns = task_active_pid_ns(current);
+
+ list_for_each_entry_safe(pos, tmp, &pidns_list, list) {
+ pid = pos->pid;
+ k = -1;
+ ns = pid->numbers[pid->level].ns;
+ /* Check whether pid has relationship with current ns */
+ for (; ns != NULL; ns = ns->parent)
+ if (ns == curr_ns)
+ k = curr_ns->level;
+ if (k == -1)
+ continue;
+ parent = proc_root;
+ for (i = k + 1; i <= pid->level; i++) {
+ ns = pid->numbers[i].ns;
+ snprintf(name_buf, 16, "pidns%u",
+ pid->numbers[i].ns->proc_inum);
+ snprintf(pid_buf, 32, "/proc/%u/ns/pid",
+ pid->numbers[0].nr);
+ /* don't duplicate ns dirs */
+ parent_new = proc_uniq_dir(parent, name_buf);
+ if (!parent_new) {
+ parent_new = proc_mkdir(name_buf, parent);
+ proc_symlink("pidns", parent_new, pid_buf);
+ }
+ parent = parent_new;
+ }
+ }
+}
+
+void proc_pidns_list(void)
+{
+ struct pid *pid;
+ struct task_struct *task = &init_task;
+
+ remove_proc_subtree(HIERARCHY_DIR, NULL);
+ proc_root = proc_mkdir(HIERARCHY_DIR, NULL);
+ free_pidns_list(&pidns_list);
+
+ do {
+ pid = task_pid(task);
+ if (pid) {
+ if (pid->level > 0)
+ ns_pid_list_add(pid);
+ }
+ } while ((task = next_task(task)) != &init_task);
+
+ print_list();
+ printk(KERN_INFO "refresh finished\n");
+}
+
+ssize_t proc_pidns_refresh_switch(struct file *file, const char __user *buf,
+ size_t size, loff_t *ppos)
+{
+ write_lock(&pidns_lock);
+ proc_pidns_list();
+ write_unlock(&pidns_lock);
+ return 1;
+}
+
+static const struct file_operations proc_pidns_refresh_fops = {
+ .write = proc_pidns_refresh_switch,
+};
+
+static int __init pidns_hierarchy_init(void)
+{
+
+ if (!proc_mkdir(BASE_DIR, NULL))
+ return -ENOMEM;
+ proc_root = proc_mkdir(HIERARCHY_DIR, NULL);
+ if (!proc_root)
+ return -ENOMEM;
+
+ proc_create(REFRESH_KEY, S_IWUGO,
+ NULL, &proc_pidns_refresh_fops);
+ printk(KERN_INFO "%s: loaded successfully\n", NAME);
+
+ return 0;
+}
+fs_initcall(pidns_hierarchy_init);
--
1.9.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/