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

Chen Hanxiao chenhanxiao at cn.fujitsu.com
Wed Sep 3 10:29:59 UTC 2014


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 at cn.fujitsu.com>
---
 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



More information about the Containers mailing list