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 <chenhanx...@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

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

Reply via email to