fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / fs / proc / base.c
index ea545e5..3e37b5f 100644 (file)
@@ -59,7 +59,7 @@
 #include <linux/string.h>
 #include <linux/seq_file.h>
 #include <linux/namei.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
 #include <linux/mm.h>
 #include <linux/smp_lock.h>
 #include <linux/rcupdate.h>
 #include <linux/mount.h>
 #include <linux/security.h>
 #include <linux/ptrace.h>
+#include <linux/tracehook.h>
 #include <linux/seccomp.h>
 #include <linux/cpuset.h>
 #include <linux/audit.h>
 #include <linux/poll.h>
+#include <linux/nsproxy.h>
+#include <linux/oom.h>
 #include <linux/vs_context.h>
 #include <linux/vs_network.h>
 
  *     in /proc for a task before it execs a suid executable.
  */
 
-/*
- * For hysterical raisins we keep the same inumbers as in the old procfs.
- * Feel free to change the macro below - just keep the range distinct from
- * inumbers of the rest of procfs (currently those are in 0x0000--0xffff).
- * As soon as we'll get a separate superblock we will be able to forget
- * about magical ranges too.
- */
-
-#define fake_ino(pid,ino) (((pid)<<16)|(ino))
-
-enum pid_directory_inos {
-       PROC_TGID_INO = 2,
-       PROC_TGID_TASK,
-       PROC_TGID_STATUS,
-       PROC_TGID_MEM,
-#ifdef CONFIG_SECCOMP
-       PROC_TGID_SECCOMP,
-#endif
-       PROC_TGID_CWD,
-       PROC_TGID_ROOT,
-       PROC_TGID_EXE,
-       PROC_TGID_FD,
-       PROC_TGID_ENVIRON,
-       PROC_TGID_AUXV,
-       PROC_TGID_CMDLINE,
-       PROC_TGID_STAT,
-       PROC_TGID_STATM,
-       PROC_TGID_MAPS,
-       PROC_TGID_NUMA_MAPS,
-       PROC_TGID_MOUNTS,
-       PROC_TGID_MOUNTSTATS,
-       PROC_TGID_WCHAN,
-#ifdef CONFIG_MMU
-       PROC_TGID_SMAPS,
-#endif
-#ifdef CONFIG_SCHEDSTATS
-       PROC_TGID_SCHEDSTAT,
-#endif
-#ifdef CONFIG_CPUSETS
-       PROC_TGID_CPUSET,
-#endif
-#ifdef CONFIG_SECURITY
-       PROC_TGID_ATTR,
-       PROC_TGID_ATTR_CURRENT,
-       PROC_TGID_ATTR_PREV,
-       PROC_TGID_ATTR_EXEC,
-       PROC_TGID_ATTR_FSCREATE,
-       PROC_TGID_ATTR_KEYCREATE,
-       PROC_TGID_ATTR_SOCKCREATE,
-#endif
-       PROC_TGID_VX_INFO,
-       PROC_TGID_IP_INFO,
-#ifdef CONFIG_AUDITSYSCALL
-       PROC_TGID_LOGINUID,
-#endif
-       PROC_TGID_OOM_SCORE,
-       PROC_TGID_OOM_ADJUST,
-       PROC_TID_INO,
-       PROC_TID_STATUS,
-       PROC_TID_MEM,
-#ifdef CONFIG_SECCOMP
-       PROC_TID_SECCOMP,
-#endif
-       PROC_TID_CWD,
-       PROC_TID_ROOT,
-       PROC_TID_EXE,
-       PROC_TID_FD,
-       PROC_TID_ENVIRON,
-       PROC_TID_AUXV,
-       PROC_TID_CMDLINE,
-       PROC_TID_STAT,
-       PROC_TID_STATM,
-       PROC_TID_MAPS,
-       PROC_TID_NUMA_MAPS,
-       PROC_TID_MOUNTS,
-       PROC_TID_MOUNTSTATS,
-       PROC_TID_WCHAN,
-#ifdef CONFIG_MMU
-       PROC_TID_SMAPS,
-#endif
-#ifdef CONFIG_SCHEDSTATS
-       PROC_TID_SCHEDSTAT,
-#endif
-#ifdef CONFIG_CPUSETS
-       PROC_TID_CPUSET,
-#endif
-#ifdef CONFIG_SECURITY
-       PROC_TID_ATTR,
-       PROC_TID_ATTR_CURRENT,
-       PROC_TID_ATTR_PREV,
-       PROC_TID_ATTR_EXEC,
-       PROC_TID_ATTR_FSCREATE,
-       PROC_TID_ATTR_KEYCREATE,
-       PROC_TID_ATTR_SOCKCREATE,
-#endif
-       PROC_TID_VX_INFO,
-       PROC_TID_IP_INFO,
-#ifdef CONFIG_AUDITSYSCALL
-       PROC_TID_LOGINUID,
-#endif
-       PROC_TID_OOM_SCORE,
-       PROC_TID_OOM_ADJUST,
-
-       /* Add new entries before this */
-       PROC_TID_FD_DIR = 0x8000,       /* 0x8000-0xffff */
-};
 
 /* Worst case buffer size needed for holding an integer. */
-#define PROC_NUMBUF 10
+#define PROC_NUMBUF 13
 
 struct pid_entry {
-       int type;
        int len;
        char *name;
        mode_t mode;
+       struct inode_operations *iop;
+       struct file_operations *fop;
+       union proc_op op;
 };
 
-#define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)}
-
-static struct pid_entry tgid_base_stuff[] = {
-       E(PROC_TGID_TASK,      "task",    S_IFDIR|S_IRUGO|S_IXUGO),
-       E(PROC_TGID_FD,        "fd",      S_IFDIR|S_IRUSR|S_IXUSR),
-       E(PROC_TGID_ENVIRON,   "environ", S_IFREG|S_IRUSR),
-       E(PROC_TGID_AUXV,      "auxv",    S_IFREG|S_IRUSR),
-       E(PROC_TGID_STATUS,    "status",  S_IFREG|S_IRUGO),
-       E(PROC_TGID_CMDLINE,   "cmdline", S_IFREG|S_IRUGO),
-       E(PROC_TGID_STAT,      "stat",    S_IFREG|S_IRUGO),
-       E(PROC_TGID_STATM,     "statm",   S_IFREG|S_IRUGO),
-       E(PROC_TGID_MAPS,      "maps",    S_IFREG|S_IRUSR),
-#ifdef CONFIG_NUMA
-       E(PROC_TGID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO),
-#endif
-       E(PROC_TGID_MEM,       "mem",     S_IFREG|S_IRUSR|S_IWUSR),
-#ifdef CONFIG_SECCOMP
-       E(PROC_TGID_SECCOMP,   "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
-#endif
-       E(PROC_TGID_CWD,       "cwd",     S_IFLNK|S_IRWXUGO),
-       E(PROC_TGID_ROOT,      "root",    S_IFLNK|S_IRWXUGO),
-       E(PROC_TGID_EXE,       "exe",     S_IFLNK|S_IRWXUGO),
-       E(PROC_TGID_MOUNTS,    "mounts",  S_IFREG|S_IRUGO),
-       E(PROC_TGID_MOUNTSTATS, "mountstats", S_IFREG|S_IRUSR),
-#ifdef CONFIG_MMU
-       E(PROC_TGID_SMAPS,     "smaps",   S_IFREG|S_IRUSR),
-#endif
-#ifdef CONFIG_SECURITY
-       E(PROC_TGID_ATTR,      "attr",    S_IFDIR|S_IRUGO|S_IXUGO),
-#endif
-#ifdef CONFIG_KALLSYMS
-       E(PROC_TGID_WCHAN,     "wchan",   S_IFREG|S_IRUGO),
-#endif
-#ifdef CONFIG_SCHEDSTATS
-       E(PROC_TGID_SCHEDSTAT, "schedstat", S_IFREG|S_IRUGO),
-#endif
-#ifdef CONFIG_CPUSETS
-       E(PROC_TGID_CPUSET,    "cpuset",  S_IFREG|S_IRUGO),
-#endif
-       E(PROC_TGID_VX_INFO,   "vinfo",   S_IFREG|S_IRUGO),
-       E(PROC_TGID_IP_INFO,   "ninfo",   S_IFREG|S_IRUGO),
-       E(PROC_TGID_OOM_SCORE, "oom_score",S_IFREG|S_IRUGO),
-       E(PROC_TGID_OOM_ADJUST,"oom_adj", S_IFREG|S_IRUGO|S_IWUSR),
-#ifdef CONFIG_AUDITSYSCALL
-       E(PROC_TGID_LOGINUID, "loginuid", S_IFREG|S_IWUSR|S_IRUGO),
-#endif
-       {0,0,NULL,0}
-};
-static struct pid_entry tid_base_stuff[] = {
-       E(PROC_TID_FD,         "fd",      S_IFDIR|S_IRUSR|S_IXUSR),
-       E(PROC_TID_ENVIRON,    "environ", S_IFREG|S_IRUSR),
-       E(PROC_TID_AUXV,       "auxv",    S_IFREG|S_IRUSR),
-       E(PROC_TID_STATUS,     "status",  S_IFREG|S_IRUGO),
-       E(PROC_TID_CMDLINE,    "cmdline", S_IFREG|S_IRUGO),
-       E(PROC_TID_STAT,       "stat",    S_IFREG|S_IRUGO),
-       E(PROC_TID_STATM,      "statm",   S_IFREG|S_IRUGO),
-       E(PROC_TID_MAPS,       "maps",    S_IFREG|S_IRUSR),
-#ifdef CONFIG_NUMA
-       E(PROC_TID_NUMA_MAPS,  "numa_maps",    S_IFREG|S_IRUGO),
-#endif
-       E(PROC_TID_MEM,        "mem",     S_IFREG|S_IRUSR|S_IWUSR),
-#ifdef CONFIG_SECCOMP
-       E(PROC_TID_SECCOMP,    "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
-#endif
-       E(PROC_TID_CWD,        "cwd",     S_IFLNK|S_IRWXUGO),
-       E(PROC_TID_ROOT,       "root",    S_IFLNK|S_IRWXUGO),
-       E(PROC_TID_EXE,        "exe",     S_IFLNK|S_IRWXUGO),
-       E(PROC_TID_MOUNTS,     "mounts",  S_IFREG|S_IRUGO),
-#ifdef CONFIG_MMU
-       E(PROC_TID_SMAPS,      "smaps",   S_IFREG|S_IRUSR),
-#endif
-#ifdef CONFIG_SECURITY
-       E(PROC_TID_ATTR,       "attr",    S_IFDIR|S_IRUGO|S_IXUGO),
-#endif
-#ifdef CONFIG_KALLSYMS
-       E(PROC_TID_WCHAN,      "wchan",   S_IFREG|S_IRUGO),
-#endif
-#ifdef CONFIG_SCHEDSTATS
-       E(PROC_TID_SCHEDSTAT, "schedstat",S_IFREG|S_IRUGO),
-#endif
-#ifdef CONFIG_CPUSETS
-       E(PROC_TID_CPUSET,     "cpuset",  S_IFREG|S_IRUGO),
-#endif
-       E(PROC_TID_VX_INFO,    "vinfo",   S_IFREG|S_IRUGO),
-       E(PROC_TID_IP_INFO,    "ninfo",   S_IFREG|S_IRUGO),
-       E(PROC_TID_OOM_SCORE,  "oom_score",S_IFREG|S_IRUGO),
-       E(PROC_TID_OOM_ADJUST, "oom_adj", S_IFREG|S_IRUGO|S_IWUSR),
-#ifdef CONFIG_AUDITSYSCALL
-       E(PROC_TID_LOGINUID, "loginuid", S_IFREG|S_IWUSR|S_IRUGO),
-#endif
-       {0,0,NULL,0}
-};
-
-#ifdef CONFIG_SECURITY
-static struct pid_entry tgid_attr_stuff[] = {
-       E(PROC_TGID_ATTR_CURRENT,  "current",  S_IFREG|S_IRUGO|S_IWUGO),
-       E(PROC_TGID_ATTR_PREV,     "prev",     S_IFREG|S_IRUGO),
-       E(PROC_TGID_ATTR_EXEC,     "exec",     S_IFREG|S_IRUGO|S_IWUGO),
-       E(PROC_TGID_ATTR_FSCREATE, "fscreate", S_IFREG|S_IRUGO|S_IWUGO),
-       E(PROC_TGID_ATTR_KEYCREATE, "keycreate", S_IFREG|S_IRUGO|S_IWUGO),
-       E(PROC_TGID_ATTR_SOCKCREATE, "sockcreate", S_IFREG|S_IRUGO|S_IWUGO),
-       {0,0,NULL,0}
-};
-static struct pid_entry tid_attr_stuff[] = {
-       E(PROC_TID_ATTR_CURRENT,   "current",  S_IFREG|S_IRUGO|S_IWUGO),
-       E(PROC_TID_ATTR_PREV,      "prev",     S_IFREG|S_IRUGO),
-       E(PROC_TID_ATTR_EXEC,      "exec",     S_IFREG|S_IRUGO|S_IWUGO),
-       E(PROC_TID_ATTR_FSCREATE,  "fscreate", S_IFREG|S_IRUGO|S_IWUGO),
-       E(PROC_TID_ATTR_KEYCREATE, "keycreate", S_IFREG|S_IRUGO|S_IWUGO),
-       E(PROC_TID_ATTR_SOCKCREATE, "sockcreate", S_IFREG|S_IRUGO|S_IWUGO),
-       {0,0,NULL,0}
-};
-#endif
-
-#undef E
-
-static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
-{
-       struct task_struct *task = get_proc_task(inode);
-       struct files_struct *files = NULL;
-       struct file *file;
-       int fd = proc_fd(inode);
-
-       if (task) {
-               files = get_files_struct(task);
-               put_task_struct(task);
-       }
-       if (files) {
-               /*
-                * We are not taking a ref to the file structure, so we must
-                * hold ->file_lock.
-                */
-               spin_lock(&files->file_lock);
-               file = fcheck_files(files, fd);
-               if (file) {
-                       *mnt = mntget(file->f_vfsmnt);
-                       *dentry = dget(file->f_dentry);
-                       spin_unlock(&files->file_lock);
-                       put_files_struct(files);
-                       return 0;
-               }
-               spin_unlock(&files->file_lock);
-               put_files_struct(files);
-       }
-       return -ENOENT;
+#define NOD(NAME, MODE, IOP, FOP, OP) {                        \
+       .len  = sizeof(NAME) - 1,                       \
+       .name = (NAME),                                 \
+       .mode = MODE,                                   \
+       .iop  = IOP,                                    \
+       .fop  = FOP,                                    \
+       .op   = OP,                                     \
 }
 
+#define DIR(NAME, MODE, OTYPE)                                                 \
+       NOD(NAME, (S_IFDIR|(MODE)),                                             \
+               &proc_##OTYPE##_inode_operations, &proc_##OTYPE##_operations,   \
+               {} )
+#define LNK(NAME, OTYPE)                                       \
+       NOD(NAME, (S_IFLNK|S_IRWXUGO),                          \
+               &proc_pid_link_inode_operations, NULL,          \
+               { .proc_get_link = &proc_##OTYPE##_link } )
+#define REG(NAME, MODE, OTYPE)                         \
+       NOD(NAME, (S_IFREG|(MODE)), NULL,               \
+               &proc_##OTYPE##_operations, {})
+#define INF(NAME, MODE, OTYPE)                         \
+       NOD(NAME, (S_IFREG|(MODE)),                     \
+               NULL, &proc_info_file_operations,       \
+               { .proc_read = &proc_##OTYPE } )
+
 static struct fs_struct *get_fs_struct(struct task_struct *task)
 {
        struct fs_struct *fs;
@@ -374,6 +151,51 @@ static int get_nr_threads(struct task_struct *tsk)
        return count;
 }
 
+static int __ptrace_may_attach(struct task_struct *task)
+{
+       /* May we inspect the given task?
+        * This check is used both for attaching with ptrace
+        * and for allowing access to sensitive information in /proc.
+        *
+        * ptrace_attach denies several cases that /proc allows
+        * because setting up the necessary parent/child relationship
+        * or halting the specified task is impossible.
+        */
+       int dumpable = 0;
+       /* Don't let security modules deny introspection */
+       if (task == current)
+               return 0;
+       if (((current->uid != task->euid) ||
+            (current->uid != task->suid) ||
+            (current->uid != task->uid) ||
+            (current->gid != task->egid) ||
+            (current->gid != task->sgid) ||
+            (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
+               return -EPERM;
+       smp_rmb();
+       if (task->mm)
+               dumpable = task->mm->dumpable;
+       if (!dumpable && !capable(CAP_SYS_PTRACE))
+               return -EPERM;
+       if (!vx_check(task->xid, VS_ADMIN_P|VS_IDENT))
+               return -EPERM;
+       if (!vx_check(task->xid, VS_IDENT) &&
+               !task_vx_flags(task, VXF_STATE_ADMIN, 0))
+               return -EACCES;
+
+       return security_ptrace(current, task);
+}
+
+int ptrace_may_attach(struct task_struct *task)
+{
+       int err;
+       task_lock(task);
+       err = __ptrace_may_attach(task);
+       task_unlock(task);
+       return !err;
+}
+
+
 static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
        struct task_struct *task = get_proc_task(inode);
@@ -416,13 +238,6 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf
        return result;
 }
 
-#define MAY_PTRACE(task) \
-       (task == current || \
-       (task->parent == current && \
-       (task->ptrace & PT_PTRACED) && \
-        (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \
-        security_ptrace(current,task) == 0))
-
 struct mm_struct *mm_for_maps(struct task_struct *task)
 {
        struct mm_struct *mm = get_task_mm(task);
@@ -612,33 +427,35 @@ struct proc_mounts {
 static int mounts_open(struct inode *inode, struct file *file)
 {
        struct task_struct *task = get_proc_task(inode);
-       struct namespace *namespace = NULL;
+       struct mnt_namespace *ns = NULL;
        struct proc_mounts *p;
        int ret = -EINVAL;
 
        if (task) {
                task_lock(task);
-               namespace = task->namespace;
-               if (namespace)
-                       get_namespace(namespace);
+               if (task->nsproxy) {
+                       ns = task->nsproxy->mnt_ns;
+                       if (ns)
+                               get_mnt_ns(ns);
+               }
                task_unlock(task);
                put_task_struct(task);
        }
 
-       if (namespace) {
+       if (ns) {
                ret = -ENOMEM;
                p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
                if (p) {
                        file->private_data = &p->m;
                        ret = seq_open(file, &mounts_op);
                        if (!ret) {
-                               p->m.private = namespace;
-                               p->event = namespace->event;
+                               p->m.private = ns;
+                               p->event = ns->event;
                                return 0;
                        }
                        kfree(p);
                }
-               put_namespace(namespace);
+               put_mnt_ns(ns);
        }
        return ret;
 }
@@ -646,15 +463,15 @@ static int mounts_open(struct inode *inode, struct file *file)
 static int mounts_release(struct inode *inode, struct file *file)
 {
        struct seq_file *m = file->private_data;
-       struct namespace *namespace = m->private;
-       put_namespace(namespace);
+       struct mnt_namespace *ns = m->private;
+       put_mnt_ns(ns);
        return seq_release(inode, file);
 }
 
 static unsigned mounts_poll(struct file *file, poll_table *wait)
 {
        struct proc_mounts *p = file->private_data;
-       struct namespace *ns = p->m.private;
+       struct mnt_namespace *ns = p->m.private;
        unsigned res = 0;
 
        poll_wait(file, &ns->poll, wait);
@@ -684,20 +501,21 @@ static int mountstats_open(struct inode *inode, struct file *file)
 
        if (!ret) {
                struct seq_file *m = file->private_data;
-               struct namespace *namespace = NULL;
+               struct mnt_namespace *mnt_ns = NULL;
                struct task_struct *task = get_proc_task(inode);
 
                if (task) {
                        task_lock(task);
-                       namespace = task->namespace;
-                       if (namespace)
-                               get_namespace(namespace);
+                       if (task->nsproxy)
+                               mnt_ns = task->nsproxy->mnt_ns;
+                       if (mnt_ns)
+                               get_mnt_ns(mnt_ns);
                        task_unlock(task);
                        put_task_struct(task);
                }
 
-               if (namespace)
-                       m->private = namespace;
+               if (mnt_ns)
+                       m->private = mnt_ns;
                else {
                        seq_release(inode, file);
                        ret = -EINVAL;
@@ -718,7 +536,7 @@ static struct file_operations proc_mountstats_operations = {
 static ssize_t proc_info_read(struct file * file, char __user * buf,
                          size_t count, loff_t *ppos)
 {
-       struct inode * inode = file->f_dentry->d_inode;
+       struct inode * inode = file->f_path.dentry->d_inode;
        unsigned long page;
        ssize_t length;
        struct task_struct *task = get_proc_task(inode);
@@ -758,7 +576,7 @@ static int mem_open(struct inode* inode, struct file* file)
 static ssize_t mem_read(struct file * file, char __user * buf,
                        size_t count, loff_t *ppos)
 {
-       struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+       struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
        char *page;
        unsigned long src = *ppos;
        int ret = -ESRCH;
@@ -767,7 +585,8 @@ static ssize_t mem_read(struct file * file, char __user * buf,
        if (!task)
                goto out_no_task;
 
-       if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
+       if (!tracehook_allow_access_process_vm(task)
+           || !ptrace_may_attach(task))
                goto out;
 
        ret = -ENOMEM;
@@ -793,7 +612,8 @@ static ssize_t mem_read(struct file * file, char __user * buf,
 
                this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
                retval = access_process_vm(task, src, page, this_len, 0);
-               if (!retval || !MAY_PTRACE(task) || !ptrace_may_attach(task)) {
+               if (!retval || !tracehook_allow_access_process_vm(task)
+                   || !ptrace_may_attach(task)) {
                        if (!ret)
                                ret = -EIO;
                        break;
@@ -828,16 +648,17 @@ out_no_task:
 static ssize_t mem_write(struct file * file, const char * buf,
                         size_t count, loff_t *ppos)
 {
-       int copied = 0;
+       int copied;
        char *page;
-       struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+       struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
        unsigned long dst = *ppos;
 
        copied = -ESRCH;
        if (!task)
                goto out_no_task;
 
-       if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
+       if (!tracehook_allow_access_process_vm(task)
+           || !ptrace_may_attach(task))
                goto out;
 
        copied = -ENOMEM;
@@ -845,6 +666,7 @@ static ssize_t mem_write(struct file * file, const char * buf,
        if (!page)
                goto out;
 
+       copied = 0;
        while (count > 0) {
                int this_len, retval;
 
@@ -899,7 +721,7 @@ static struct file_operations proc_mem_operations = {
 static ssize_t oom_adjust_read(struct file *file, char __user *buf,
                                size_t count, loff_t *ppos)
 {
-       struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+       struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
        char buffer[PROC_NUMBUF];
        size_t len;
        int oom_adjust;
@@ -928,21 +750,24 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
        char buffer[PROC_NUMBUF], *end;
        int oom_adjust;
 
-       if (!capable(CAP_SYS_RESOURCE))
-               return -EPERM;
        memset(buffer, 0, sizeof(buffer));
        if (count > sizeof(buffer) - 1)
                count = sizeof(buffer) - 1;
        if (copy_from_user(buffer, buf, count))
                return -EFAULT;
        oom_adjust = simple_strtol(buffer, &end, 0);
-       if ((oom_adjust < -16 || oom_adjust > 15) && oom_adjust != OOM_DISABLE)
+       if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) &&
+            oom_adjust != OOM_DISABLE)
                return -EINVAL;
        if (*end == '\n')
                end++;
-       task = get_proc_task(file->f_dentry->d_inode);
+       task = get_proc_task(file->f_path.dentry->d_inode);
        if (!task)
                return -ESRCH;
+       if (oom_adjust < task->oomkilladj && !capable(CAP_SYS_RESOURCE)) {
+               put_task_struct(task);
+               return -EACCES;
+       }
        task->oomkilladj = oom_adjust;
        put_task_struct(task);
        if (end - buffer == 0)
@@ -960,7 +785,7 @@ static struct file_operations proc_oom_adjust_operations = {
 static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
                                  size_t count, loff_t *ppos)
 {
-       struct inode * inode = file->f_dentry->d_inode;
+       struct inode * inode = file->f_path.dentry->d_inode;
        struct task_struct *task = get_proc_task(inode);
        ssize_t length;
        char tmpbuf[TMPBUFLEN];
@@ -976,7 +801,7 @@ static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
 static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
                                   size_t count, loff_t *ppos)
 {
-       struct inode * inode = file->f_dentry->d_inode;
+       struct inode * inode = file->f_path.dentry->d_inode;
        char *page, *tmp;
        ssize_t length;
        uid_t loginuid;
@@ -1095,6 +920,65 @@ static struct file_operations proc_seccomp_operations = {
 };
 #endif /* CONFIG_SECCOMP */
 
+#ifdef CONFIG_FAULT_INJECTION
+static ssize_t proc_fault_inject_read(struct file * file, char __user * buf,
+                                     size_t count, loff_t *ppos)
+{
+       struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+       char buffer[PROC_NUMBUF];
+       size_t len;
+       int make_it_fail;
+       loff_t __ppos = *ppos;
+
+       if (!task)
+               return -ESRCH;
+       make_it_fail = task->make_it_fail;
+       put_task_struct(task);
+
+       len = snprintf(buffer, sizeof(buffer), "%i\n", make_it_fail);
+       if (__ppos >= len)
+               return 0;
+       if (count > len-__ppos)
+               count = len-__ppos;
+       if (copy_to_user(buf, buffer + __ppos, count))
+               return -EFAULT;
+       *ppos = __ppos + count;
+       return count;
+}
+
+static ssize_t proc_fault_inject_write(struct file * file,
+                       const char __user * buf, size_t count, loff_t *ppos)
+{
+       struct task_struct *task;
+       char buffer[PROC_NUMBUF], *end;
+       int make_it_fail;
+
+       if (!capable(CAP_SYS_RESOURCE))
+               return -EPERM;
+       memset(buffer, 0, sizeof(buffer));
+       if (count > sizeof(buffer) - 1)
+               count = sizeof(buffer) - 1;
+       if (copy_from_user(buffer, buf, count))
+               return -EFAULT;
+       make_it_fail = simple_strtol(buffer, &end, 0);
+       if (*end == '\n')
+               end++;
+       task = get_proc_task(file->f_dentry->d_inode);
+       if (!task)
+               return -ESRCH;
+       task->make_it_fail = make_it_fail;
+       put_task_struct(task);
+       if (end - buffer == 0)
+               return -EIO;
+       return end - buffer;
+}
+
+static struct file_operations proc_fault_inject_operations = {
+       .read           = proc_fault_inject_read,
+       .write          = proc_fault_inject_write,
+};
+#endif
+
 static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
        struct inode *inode = dentry->d_inode;
@@ -1167,192 +1051,45 @@ static struct inode_operations proc_pid_link_inode_operations = {
        .setattr        = proc_setattr,
 };
 
-static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
-{
-       struct dentry *dentry = filp->f_dentry;
-       struct inode *inode = dentry->d_inode;
-       struct task_struct *p = get_proc_task(inode);
-       unsigned int fd, tid, ino;
-       int retval;
-       char buf[PROC_NUMBUF];
-       struct files_struct * files;
-       struct fdtable *fdt;
-
-       retval = -ENOENT;
-       if (!p)
-               goto out_no_task;
-       retval = 0;
-       tid = p->pid;
-
-       fd = filp->f_pos;
-       switch (fd) {
-               case 0:
-                       if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
-                               goto out;
-                       filp->f_pos++;
-               case 1:
-                       ino = parent_ino(dentry);
-                       if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
-                               goto out;
-                       filp->f_pos++;
-               default:
-                       files = get_files_struct(p);
-                       if (!files)
-                               goto out;
-                       rcu_read_lock();
-                       fdt = files_fdtable(files);
-                       for (fd = filp->f_pos-2;
-                            fd < fdt->max_fds;
-                            fd++, filp->f_pos++) {
-                               unsigned int i,j;
 
-                               if (!fcheck_files(files, fd))
-                                       continue;
-                               rcu_read_unlock();
+/* building an inode */
 
-                               j = PROC_NUMBUF;
-                               i = fd;
-                               do {
-                                       j--;
-                                       buf[j] = '0' + (i % 10);
-                                       i /= 10;
-                               } while (i);
+static int task_dumpable(struct task_struct *task)
+{
+       int dumpable = 0;
+       struct mm_struct *mm;
 
-                               ino = fake_ino(tid, PROC_TID_FD_DIR + fd);
-                               if (filldir(dirent, buf+j, PROC_NUMBUF-j, fd+2, ino, DT_LNK) < 0) {
-                                       rcu_read_lock();
-                                       break;
-                               }
-                               rcu_read_lock();
-                       }
-                       rcu_read_unlock();
-                       put_files_struct(files);
-       }
-out:
-       put_task_struct(p);
-out_no_task:
-       return retval;
+       task_lock(task);
+       mm = task->mm;
+       if (mm)
+               dumpable = mm->dumpable;
+       task_unlock(task);
+       if(dumpable == 1)
+               return 1;
+       return 0;
 }
 
-static int proc_pident_readdir(struct file *filp,
-               void *dirent, filldir_t filldir,
-               struct pid_entry *ents, unsigned int nents)
+
+static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task)
 {
-       int i;
-       int pid;
-       struct dentry *dentry = filp->f_dentry;
-       struct inode *inode = dentry->d_inode;
-       struct task_struct *task = get_proc_task(inode);
-       struct pid_entry *p;
-       ino_t ino;
-       int ret, hide;
+       struct inode * inode;
+       struct proc_inode *ei;
 
-       ret = -ENOENT;
-       if (!task)
-               goto out;
-
-       ret = 0;
-       pid = task->pid;
-       put_task_struct(task);
-       i = filp->f_pos;
-       switch (i) {
-       case 0:
-               ino = inode->i_ino;
-               if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
-                       goto out;
-               i++;
-               filp->f_pos++;
-               /* fall through */
-       case 1:
-               ino = parent_ino(dentry);
-               if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
-                       goto out;
-               i++;
-               filp->f_pos++;
-               /* fall through */
-       default:
-               i -= 2;
-               if (i >= nents) {
-                       ret = 1;
-                       goto out;
-               }
-               p = ents + i;
-               hide = vx_flags(VXF_INFO_HIDE, 0);
-               while (p->name) {
-                       if (hide) {
-                               switch (p->type) {
-                               case PROC_TGID_VX_INFO:
-                               case PROC_TGID_IP_INFO:
-                                       goto skip;
-                               }
-                       }
-                       if (filldir(dirent, p->name, p->len, filp->f_pos,
-                                   fake_ino(pid, p->type), p->mode >> 12) < 0)
-                               goto out;
-                       filp->f_pos++;
-               skip:
-                       p++;
-               }
-       }
-
-       ret = 1;
-out:
-       return ret;
-}
-
-static int proc_tgid_base_readdir(struct file * filp,
-                            void * dirent, filldir_t filldir)
-{
-       return proc_pident_readdir(filp,dirent,filldir,
-                                  tgid_base_stuff,ARRAY_SIZE(tgid_base_stuff));
-}
-
-static int proc_tid_base_readdir(struct file * filp,
-                            void * dirent, filldir_t filldir)
-{
-       return proc_pident_readdir(filp,dirent,filldir,
-                                  tid_base_stuff,ARRAY_SIZE(tid_base_stuff));
-}
-
-/* building an inode */
-
-static int task_dumpable(struct task_struct *task)
-{
-       int dumpable = 0;
-       struct mm_struct *mm;
-
-       task_lock(task);
-       mm = task->mm;
-       if (mm)
-               dumpable = mm->dumpable;
-       task_unlock(task);
-       if(dumpable == 1)
-               return 1;
-       return 0;
-}
-
-
-static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task, int ino)
-{
-       struct inode * inode;
-       struct proc_inode *ei;
-
-       /* We need a new inode */
-       
-       inode = new_inode(sb);
-       if (!inode)
+       /* We need a new inode */
+
+       inode = new_inode(sb);
+       if (!inode)
                goto out;
 
        /* Common stuff */
        ei = PROC_I(inode);
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-       inode->i_ino = fake_ino(task->pid, ino);
        inode->i_op = &proc_def_inode_operations;
 
        /*
         * grab the reference to task.
         */
-       ei->pid = get_pid(task->pids[PIDTYPE_PID].pid);
+       ei->pid = get_task_pid(task, PIDTYPE_PID);
        if (!ei->pid)
                goto out_unlock;
 
@@ -1362,7 +1099,8 @@ static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_st
                inode->i_uid = task->euid;
                inode->i_gid = task->egid;
        }
-       inode->i_xid = vx_task_xid(task);
+       /* procfs is xid tagged */
+       inode->i_tag = (tag_t)vx_task_xid(task);
        security_task_to_inode(task, inode);
 
 out:
@@ -1373,6 +1111,27 @@ out_unlock:
        return NULL;
 }
 
+static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+{
+       struct inode *inode = dentry->d_inode;
+       struct task_struct *task;
+       generic_fillattr(inode, stat);
+
+       rcu_read_lock();
+       stat->uid = 0;
+       stat->gid = 0;
+       task = pid_task(proc_pid(inode), PIDTYPE_PID);
+       if (task) {
+               if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
+                   task_dumpable(task)) {
+                       stat->uid = task->euid;
+                       stat->gid = task->egid;
+               }
+       }
+       rcu_read_unlock();
+       return 0;
+}
+
 /* dentry stuff */
 
 /*
@@ -1394,15 +1153,7 @@ static int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
        struct inode *inode = dentry->d_inode;
        struct task_struct *task = get_proc_task(inode);
-       int ret = 0;
-
        if (task) {
-               int pid = (inode->i_ino >> 16) & 0xFFFF;
-
-               if (!proc_pid_visible(task, pid))
-                       goto out_drop;
-
-               ret = 1;
                if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
                    task_dumpable(task)) {
                        inode->i_uid = task->euid;
@@ -1413,35 +1164,137 @@ static int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
                }
                inode->i_mode &= ~(S_ISUID | S_ISGID);
                security_task_to_inode(task, inode);
-               goto out_put;
+               put_task_struct(task);
+               return 1;
        }
-out_drop:
        d_drop(dentry);
-out_put:
-       if (task)
-               put_task_struct(task);
-       return ret;
+       return 0;
 }
 
-static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+static int pid_delete_dentry(struct dentry * dentry)
 {
-       struct inode *inode = dentry->d_inode;
-       struct task_struct *task;
-       generic_fillattr(inode, stat);
+       /* Is the task we represent dead?
+        * If so, then don't put the dentry on the lru list,
+        * kill it immediately.
+        */
+       return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first;
+}
+
+static struct dentry_operations pid_dentry_operations =
+{
+       .d_revalidate   = pid_revalidate,
+       .d_delete       = pid_delete_dentry,
+};
+
+/* Lookups */
+
+typedef struct dentry *instantiate_t(struct inode *, struct dentry *, struct task_struct *, void *);
+
+/*
+ * Fill a directory entry.
+ *
+ * If possible create the dcache entry and derive our inode number and
+ * file type from dcache entry.
+ *
+ * Since all of the proc inode numbers are dynamically generated, the inode
+ * numbers do not exist until the inode is cache.  This means creating the
+ * the dcache entry in readdir is necessary to keep the inode numbers
+ * reported by readdir in sync with the inode numbers reported
+ * by stat.
+ */
+static int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+       char *name, int len,
+       instantiate_t instantiate, struct task_struct *task, void *ptr)
+{
+       struct dentry *child, *dir = filp->f_path.dentry;
+       struct inode *inode;
+       struct qstr qname;
+       ino_t ino = 0;
+       unsigned type = DT_UNKNOWN;
+
+       qname.name = name;
+       qname.len  = len;
+       qname.hash = full_name_hash(name, len);
+
+       child = d_lookup(dir, &qname);
+       if (!child) {
+               struct dentry *new;
+               new = d_alloc(dir, &qname);
+               if (new) {
+                       child = instantiate(dir->d_inode, new, task, ptr);
+                       if (child)
+                               dput(new);
+                       else
+                               child = new;
+               }
+       }
+       if (!child || IS_ERR(child) || !child->d_inode)
+               goto end_instantiate;
+       inode = child->d_inode;
+       if (inode) {
+               ino = inode->i_ino;
+               type = inode->i_mode >> 12;
+       }
+       dput(child);
+end_instantiate:
+       if (!ino)
+               ino = find_inode_number(dir, &qname);
+       if (!ino)
+               ino = 1;
+       return filldir(dirent, name, len, filp->f_pos, ino, type);
+}
+
+static unsigned name_to_int(struct dentry *dentry)
+{
+       const char *name = dentry->d_name.name;
+       int len = dentry->d_name.len;
+       unsigned n = 0;
+
+       if (len > 1 && *name == '0')
+               goto out;
+       while (len-- > 0) {
+               unsigned c = *name++ - '0';
+               if (c > 9)
+                       goto out;
+               if (n >= (~0U-9)/10)
+                       goto out;
+               n *= 10;
+               n += c;
+       }
+       return n;
+out:
+       return ~0U;
+}
+
+static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+{
+       struct task_struct *task = get_proc_task(inode);
+       struct files_struct *files = NULL;
+       struct file *file;
+       int fd = proc_fd(inode);
 
-       rcu_read_lock();
-       stat->uid = 0;
-       stat->gid = 0;
-       task = pid_task(proc_pid(inode), PIDTYPE_PID);
        if (task) {
-               if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
-                   task_dumpable(task)) {
-                       stat->uid = task->euid;
-                       stat->gid = task->egid;
+               files = get_files_struct(task);
+               put_task_struct(task);
+       }
+       if (files) {
+               /*
+                * We are not taking a ref to the file structure, so we must
+                * hold ->file_lock.
+                */
+               spin_lock(&files->file_lock);
+               file = fcheck_files(files, fd);
+               if (file) {
+                       *mnt = mntget(file->f_path.mnt);
+                       *dentry = dget(file->f_path.dentry);
+                       spin_unlock(&files->file_lock);
+                       put_files_struct(files);
+                       return 0;
                }
+               spin_unlock(&files->file_lock);
+               put_files_struct(files);
        }
-       rcu_read_unlock();
-       return 0;
+       return -ENOENT;
 }
 
 static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
@@ -1479,75 +1332,30 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
        return 0;
 }
 
-static int pid_delete_dentry(struct dentry * dentry)
-{
-       /* Is the task we represent dead?
-        * If so, then don't put the dentry on the lru list,
-        * kill it immediately.
-        */
-       return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first;
-}
-
 static struct dentry_operations tid_fd_dentry_operations =
 {
        .d_revalidate   = tid_fd_revalidate,
        .d_delete       = pid_delete_dentry,
 };
 
-static struct dentry_operations pid_dentry_operations =
-{
-       .d_revalidate   = pid_revalidate,
-       .d_delete       = pid_delete_dentry,
-};
-
-/* Lookups */
-
-static unsigned name_to_int(struct dentry *dentry)
-{
-       const char *name = dentry->d_name.name;
-       int len = dentry->d_name.len;
-       unsigned n = 0;
-
-       if (len > 1 && *name == '0')
-               goto out;
-       while (len-- > 0) {
-               unsigned c = *name++ - '0';
-               if (c > 9)
-                       goto out;
-               if (n >= (~0U-9)/10)
-                       goto out;
-               n *= 10;
-               n += c;
-       }
-       return n;
-out:
-       return ~0U;
-}
-
-/* SMP-safe */
-static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+static struct dentry *proc_fd_instantiate(struct inode *dir,
+       struct dentry *dentry, struct task_struct *task, void *ptr)
 {
-       struct task_struct *task = get_proc_task(dir);
-       unsigned fd = name_to_int(dentry);
-       struct dentry *result = ERR_PTR(-ENOENT);
-       struct file * file;
-       struct files_struct * files;
-       struct inode *inode;
-       struct proc_inode *ei;
-
-       if (!task)
-               goto out_no_task;
-       if (fd == ~0U)
-               goto out;
+       unsigned fd = *(unsigned *)ptr;
+       struct file *file;
+       struct files_struct *files;
+       struct inode *inode;
+       struct proc_inode *ei;
+       struct dentry *error = ERR_PTR(-ENOENT);
 
-       inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_FD_DIR+fd);
+       inode = proc_pid_make_inode(dir->i_sb, task);
        if (!inode)
                goto out;
        ei = PROC_I(inode);
        ei->fd = fd;
        files = get_files_struct(task);
        if (!files)
-               goto out_unlock;
+               goto out_iput;
        inode->i_mode = S_IFLNK;
 
        /*
@@ -1557,13 +1365,14 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
        spin_lock(&files->file_lock);
        file = fcheck_files(files, fd);
        if (!file)
-               goto out_unlock2;
+               goto out_unlock;
        if (file->f_mode & 1)
                inode->i_mode |= S_IRUSR | S_IXUSR;
        if (file->f_mode & 2)
                inode->i_mode |= S_IWUSR | S_IXUSR;
        spin_unlock(&files->file_lock);
        put_files_struct(files);
+
        inode->i_op = &proc_pid_link_inode_operations;
        inode->i_size = 64;
        ei->op.proc_get_link = proc_fd_link;
@@ -1571,34 +1380,106 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
        if (tid_fd_revalidate(dentry, NULL))
-               result = NULL;
-out:
-       put_task_struct(task);
-out_no_task:
-       return result;
+               error = NULL;
 
-out_unlock2:
+ out:
+       return error;
+out_unlock:
        spin_unlock(&files->file_lock);
        put_files_struct(files);
-out_unlock:
+out_iput:
        iput(inode);
        goto out;
 }
 
-static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir);
-static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd);
-static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
+static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+{
+       struct task_struct *task = get_proc_task(dir);
+       unsigned fd = name_to_int(dentry);
+       struct dentry *result = ERR_PTR(-ENOENT);
+
+       if (!task)
+               goto out_no_task;
+       if (fd == ~0U)
+               goto out;
+
+       result = proc_fd_instantiate(dir, dentry, task, &fd);
+out:
+       put_task_struct(task);
+out_no_task:
+       return result;
+}
+
+static int proc_fd_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+       struct task_struct *task, int fd)
+{
+       char name[PROC_NUMBUF];
+       int len = snprintf(name, sizeof(name), "%d", fd);
+       return proc_fill_cache(filp, dirent, filldir, name, len,
+                               proc_fd_instantiate, task, &fd);
+}
+
+static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
+{
+       struct dentry *dentry = filp->f_path.dentry;
+       struct inode *inode = dentry->d_inode;
+       struct task_struct *p = get_proc_task(inode);
+       unsigned int fd, tid, ino;
+       int retval;
+       struct files_struct * files;
+       struct fdtable *fdt;
+
+       retval = -ENOENT;
+       if (!p)
+               goto out_no_task;
+       retval = 0;
+       tid = p->pid;
+
+       fd = filp->f_pos;
+       switch (fd) {
+               case 0:
+                       if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
+                               goto out;
+                       filp->f_pos++;
+               case 1:
+                       ino = parent_ino(dentry);
+                       if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
+                               goto out;
+                       filp->f_pos++;
+               default:
+                       files = get_files_struct(p);
+                       if (!files)
+                               goto out;
+                       rcu_read_lock();
+                       fdt = files_fdtable(files);
+                       for (fd = filp->f_pos-2;
+                            fd < fdt->max_fds;
+                            fd++, filp->f_pos++) {
+
+                               if (!fcheck_files(files, fd))
+                                       continue;
+                               rcu_read_unlock();
+
+                               if (proc_fd_fill_cache(filp, dirent, filldir, p, fd) < 0) {
+                                       rcu_read_lock();
+                                       break;
+                               }
+                               rcu_read_lock();
+                       }
+                       rcu_read_unlock();
+                       put_files_struct(files);
+       }
+out:
+       put_task_struct(p);
+out_no_task:
+       return retval;
+}
 
 static struct file_operations proc_fd_operations = {
        .read           = generic_read_dir,
        .readdir        = proc_readfd,
 };
 
-static struct file_operations proc_task_operations = {
-       .read           = generic_read_dir,
-       .readdir        = proc_task_readdir,
-};
-
 /*
  * proc directories can do almost nothing..
  */
@@ -1607,17 +1488,150 @@ static struct inode_operations proc_fd_inode_operations = {
        .setattr        = proc_setattr,
 };
 
-static struct inode_operations proc_task_inode_operations = {
-       .lookup         = proc_task_lookup,
-       .getattr        = proc_task_getattr,
-       .setattr        = proc_setattr,
-};
+static struct dentry *proc_pident_instantiate(struct inode *dir,
+       struct dentry *dentry, struct task_struct *task, void *ptr)
+{
+       struct pid_entry *p = ptr;
+       struct inode *inode;
+       struct proc_inode *ei;
+       struct dentry *error = ERR_PTR(-EINVAL);
+
+       inode = proc_pid_make_inode(dir->i_sb, task);
+       if (!inode)
+               goto out;
+
+       ei = PROC_I(inode);
+       inode->i_mode = p->mode;
+       if (S_ISDIR(inode->i_mode))
+               inode->i_nlink = 2;     /* Use getattr to fix if necessary */
+       if (p->iop)
+               inode->i_op = p->iop;
+       if (p->fop)
+               inode->i_fop = p->fop;
+       ei->op = p->op;
+       dentry->d_op = &pid_dentry_operations;
+       d_add(dentry, inode);
+       /* Close the race of the process dying before we return the dentry */
+       if (pid_revalidate(dentry, NULL))
+               error = NULL;
+out:
+       return error;
+}
+
+static struct dentry *proc_pident_lookup(struct inode *dir, 
+                                        struct dentry *dentry,
+                                        struct pid_entry *ents,
+                                        unsigned int nents)
+{
+       struct inode *inode;
+       struct dentry *error;
+       struct task_struct *task = get_proc_task(dir);
+       struct pid_entry *p, *last;
+
+       error = ERR_PTR(-ENOENT);
+       inode = NULL;
+
+       if (!task)
+               goto out_no_task;
+
+       /* TODO: maybe we can come up with a generic approach? */
+       if (task_vx_flags(task, VXF_HIDE_VINFO, 0) &&
+               (dentry->d_name.len == 5) &&
+               (!memcmp(dentry->d_name.name, "vinfo", 5) ||
+               !memcmp(dentry->d_name.name, "ninfo", 5)))
+               goto out;
+
+       /*
+        * Yes, it does not scale. And it should not. Don't add
+        * new entries into /proc/<tgid>/ without very good reasons.
+        */
+       last = &ents[nents - 1];
+       for (p = ents; p <= last; p++) {
+               if (p->len != dentry->d_name.len)
+                       continue;
+               if (!memcmp(dentry->d_name.name, p->name, p->len))
+                       break;
+       }
+       if (p > last)
+               goto out;
+
+       error = proc_pident_instantiate(dir, dentry, task, p);
+out:
+       put_task_struct(task);
+out_no_task:
+       return error;
+}
+
+static int proc_pident_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+       struct task_struct *task, struct pid_entry *p)
+{
+       return proc_fill_cache(filp, dirent, filldir, p->name, p->len,
+                               proc_pident_instantiate, task, p);
+}
+
+static int proc_pident_readdir(struct file *filp,
+               void *dirent, filldir_t filldir,
+               struct pid_entry *ents, unsigned int nents)
+{
+       int i;
+       int pid;
+       struct dentry *dentry = filp->f_path.dentry;
+       struct inode *inode = dentry->d_inode;
+       struct task_struct *task = get_proc_task(inode);
+       struct pid_entry *p, *last;
+       ino_t ino;
+       int ret;
+
+       ret = -ENOENT;
+       if (!task)
+               goto out_no_task;
+
+       ret = 0;
+       pid = task->pid;
+       i = filp->f_pos;
+       switch (i) {
+       case 0:
+               ino = inode->i_ino;
+               if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
+                       goto out;
+               i++;
+               filp->f_pos++;
+               /* fall through */
+       case 1:
+               ino = parent_ino(dentry);
+               if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
+                       goto out;
+               i++;
+               filp->f_pos++;
+               /* fall through */
+       default:
+               i -= 2;
+               if (i >= nents) {
+                       ret = 1;
+                       goto out;
+               }
+               p = ents + i;
+               last = &ents[nents - 1];
+               while (p <= last) {
+                       if (proc_pident_fill_cache(filp, dirent, filldir, task, p) < 0)
+                               goto out;
+                       filp->f_pos++;
+                       p++;
+               }
+       }
+
+       ret = 1;
+out:
+       put_task_struct(task);
+out_no_task:
+       return ret;
+}
 
 #ifdef CONFIG_SECURITY
 static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
                                  size_t count, loff_t *ppos)
 {
-       struct inode * inode = file->f_dentry->d_inode;
+       struct inode * inode = file->f_path.dentry->d_inode;
        unsigned long page;
        ssize_t length;
        struct task_struct *task = get_proc_task(inode);
@@ -1632,8 +1646,8 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
        if (!(page = __get_free_page(GFP_KERNEL)))
                goto out;
 
-       length = security_getprocattr(task, 
-                                     (char*)file->f_dentry->d_name.name, 
+       length = security_getprocattr(task,
+                                     (char*)file->f_path.dentry->d_name.name,
                                      (void*)page, count);
        if (length >= 0)
                length = simple_read_from_buffer(buf, count, ppos, (char *)page, length);
@@ -1646,17 +1660,17 @@ out_no_task:
 
 static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
                                   size_t count, loff_t *ppos)
-{ 
-       struct inode * inode = file->f_dentry->d_inode;
-       char *page; 
-       ssize_t length; 
+{
+       struct inode * inode = file->f_path.dentry->d_inode;
+       char *page;
+       ssize_t length;
        struct task_struct *task = get_proc_task(inode);
 
        length = -ESRCH;
        if (!task)
                goto out_no_task;
-       if (count > PAGE_SIZE) 
-               count = PAGE_SIZE; 
+       if (count > PAGE_SIZE)
+               count = PAGE_SIZE;
 
        /* No partial writes. */
        length = -EINVAL;
@@ -1664,16 +1678,16 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
                goto out;
 
        length = -ENOMEM;
-       page = (char*)__get_free_page(GFP_USER); 
-       if (!page) 
+       page = (char*)__get_free_page(GFP_USER);
+       if (!page)
                goto out;
 
-       length = -EFAULT; 
-       if (copy_from_user(page, buf, count)) 
+       length = -EFAULT;
+       if (copy_from_user(page, buf, count))
                goto out_free;
 
-       length = security_setprocattr(task, 
-                                     (char*)file->f_dentry->d_name.name, 
+       length = security_setprocattr(task,
+                                     (char*)file->f_path.dentry->d_name.name,
                                      (void*)page, count);
 out_free:
        free_page((unsigned long) page);
@@ -1681,353 +1695,294 @@ out:
        put_task_struct(task);
 out_no_task:
        return length;
-} 
+}
 
 static struct file_operations proc_pid_attr_operations = {
        .read           = proc_pid_attr_read,
        .write          = proc_pid_attr_write,
 };
 
-static struct file_operations proc_tid_attr_operations;
-static struct inode_operations proc_tid_attr_inode_operations;
-static struct file_operations proc_tgid_attr_operations;
-static struct inode_operations proc_tgid_attr_inode_operations;
+static struct pid_entry attr_dir_stuff[] = {
+       REG("current",    S_IRUGO|S_IWUGO, pid_attr),
+       REG("prev",       S_IRUGO,         pid_attr),
+       REG("exec",       S_IRUGO|S_IWUGO, pid_attr),
+       REG("fscreate",   S_IRUGO|S_IWUGO, pid_attr),
+       REG("keycreate",  S_IRUGO|S_IWUGO, pid_attr),
+       REG("sockcreate", S_IRUGO|S_IWUGO, pid_attr),
+};
+
+static int proc_attr_dir_readdir(struct file * filp,
+                            void * dirent, filldir_t filldir)
+{
+       return proc_pident_readdir(filp,dirent,filldir,
+                                  attr_dir_stuff,ARRAY_SIZE(attr_dir_stuff));
+}
+
+static struct file_operations proc_attr_dir_operations = {
+       .read           = generic_read_dir,
+       .readdir        = proc_attr_dir_readdir,
+};
+
+static struct dentry *proc_attr_dir_lookup(struct inode *dir,
+                               struct dentry *dentry, struct nameidata *nd)
+{
+       return proc_pident_lookup(dir, dentry,
+                                 attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff));
+}
+
+static struct inode_operations proc_attr_dir_inode_operations = {
+       .lookup         = proc_attr_dir_lookup,
+       .getattr        = pid_getattr,
+       .setattr        = proc_setattr,
+};
+
 #endif
 
-extern int proc_pid_vx_info(struct task_struct *, char *);
-extern int proc_pid_nx_info(struct task_struct *, char *);
+/*
+ * /proc/self:
+ */
+static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
+                             int buflen)
+{
+       char tmp[PROC_NUMBUF];
+       sprintf(tmp, "%d", vx_map_tgid(current->tgid));
+       return vfs_readlink(dentry,buffer,buflen,tmp);
+}
 
-/* SMP-safe */
-static struct dentry *proc_pident_lookup(struct inode *dir, 
-                                        struct dentry *dentry,
-                                        struct pid_entry *ents)
+static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+       char tmp[PROC_NUMBUF];
+       sprintf(tmp, "%d", vx_map_tgid(current->tgid));
+       return ERR_PTR(vfs_follow_link(nd,tmp));
+}
+
+static struct inode_operations proc_self_inode_operations = {
+       .readlink       = proc_self_readlink,
+       .follow_link    = proc_self_follow_link,
+};
+
+/*
+ * proc base
+ *
+ * These are the directory entries in the root directory of /proc
+ * that properly belong to the /proc filesystem, as they describe
+ * describe something that is process related.
+ */
+static struct pid_entry proc_base_stuff[] = {
+       NOD("self", S_IFLNK|S_IRWXUGO,
+               &proc_self_inode_operations, NULL, {}),
+};
+
+/*
+ *     Exceptional case: normally we are not allowed to unhash a busy
+ * directory. In this case, however, we can do it - no aliasing problems
+ * due to the way we treat inodes.
+ */
+static int proc_base_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+       struct inode *inode = dentry->d_inode;
+       struct task_struct *task = get_proc_task(inode);
+       if (task) {
+               put_task_struct(task);
+               return 1;
+       }
+       d_drop(dentry);
+       return 0;
+}
+
+static struct dentry_operations proc_base_dentry_operations =
+{
+       .d_revalidate   = proc_base_revalidate,
+       .d_delete       = pid_delete_dentry,
+};
+
+static struct dentry *proc_base_instantiate(struct inode *dir,
+       struct dentry *dentry, struct task_struct *task, void *ptr)
 {
+       struct pid_entry *p = ptr;
        struct inode *inode;
-       struct dentry *error;
-       struct task_struct *task = get_proc_task(dir);
-       struct pid_entry *p;
        struct proc_inode *ei;
+       struct dentry *error = ERR_PTR(-EINVAL);
+
+       /* Allocate the inode */
+       error = ERR_PTR(-ENOMEM);
+       inode = new_inode(dir->i_sb);
+       if (!inode)
+               goto out;
+
+       /* Initialize the inode */
+       ei = PROC_I(inode);
+       inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+
+       /*
+        * grab the reference to the task.
+        */
+       ei->pid = get_task_pid(task, PIDTYPE_PID);
+       if (!ei->pid)
+               goto out_iput;
+
+       inode->i_uid = 0;
+       inode->i_gid = 0;
+       inode->i_mode = p->mode;
+       if (S_ISDIR(inode->i_mode))
+               inode->i_nlink = 2;
+       if (S_ISLNK(inode->i_mode))
+               inode->i_size = 64;
+       if (p->iop)
+               inode->i_op = p->iop;
+       if (p->fop)
+               inode->i_fop = p->fop;
+       ei->op = p->op;
+       dentry->d_op = &proc_base_dentry_operations;
+       d_add(dentry, inode);
+       error = NULL;
+out:
+       return error;
+out_iput:
+       iput(inode);
+       goto out;
+}
+
+static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
+{
+       struct dentry *error;
+       struct task_struct *task = get_proc_task_real(dir);
+       struct pid_entry *p, *last;
 
        error = ERR_PTR(-ENOENT);
-       inode = NULL;
 
        if (!task)
                goto out_no_task;
 
-       for (p = ents; p->name; p++) {
+       /* Lookup the directory entry */
+       last = &proc_base_stuff[ARRAY_SIZE(proc_base_stuff) - 1];
+       for (p = proc_base_stuff; p <= last; p++) {
                if (p->len != dentry->d_name.len)
                        continue;
                if (!memcmp(dentry->d_name.name, p->name, p->len))
                        break;
        }
-       if (!p->name)
+       if (p > last)
                goto out;
 
-       switch(p->type) {
-               case PROC_TID_VX_INFO:
-               case PROC_TGID_VX_INFO:
-               case PROC_TID_IP_INFO:
-               case PROC_TGID_IP_INFO:
-                       if (task_vx_flags(task, VXF_INFO_HIDE, 0))
-                               goto out;
-               default:
-                       break;
-       }
+       error = proc_base_instantiate(dir, dentry, task, p);
 
-       error = ERR_PTR(-EINVAL);
-       inode = proc_pid_make_inode(dir->i_sb, task, p->type);
-       if (!inode)
-               goto out;
+out:
+       put_task_struct(task);
+out_no_task:
+       return error;
+}
 
-       ei = PROC_I(inode);
-       inode->i_mode = p->mode;
-       /*
-        * Yes, it does not scale. And it should not. Don't add
-        * new entries into /proc/<tgid>/ without very good reasons.
-        */
-       switch(p->type) {
-               case PROC_TGID_TASK:
-                       inode->i_nlink = 2;
-                       inode->i_op = &proc_task_inode_operations;
-                       inode->i_fop = &proc_task_operations;
-                       break;
-               case PROC_TID_FD:
-               case PROC_TGID_FD:
-                       inode->i_nlink = 2;
-                       inode->i_op = &proc_fd_inode_operations;
-                       inode->i_fop = &proc_fd_operations;
-                       break;
-               case PROC_TID_EXE:
-               case PROC_TGID_EXE:
-                       inode->i_op = &proc_pid_link_inode_operations;
-                       ei->op.proc_get_link = proc_exe_link;
-                       break;
-               case PROC_TID_CWD:
-               case PROC_TGID_CWD:
-                       inode->i_op = &proc_pid_link_inode_operations;
-                       ei->op.proc_get_link = proc_cwd_link;
-                       break;
-               case PROC_TID_ROOT:
-               case PROC_TGID_ROOT:
-                       inode->i_op = &proc_pid_link_inode_operations;
-                       ei->op.proc_get_link = proc_root_link;
-                       break;
-               case PROC_TID_ENVIRON:
-               case PROC_TGID_ENVIRON:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_pid_environ;
-                       break;
-               case PROC_TID_AUXV:
-               case PROC_TGID_AUXV:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_pid_auxv;
-                       break;
-               case PROC_TID_STATUS:
-               case PROC_TGID_STATUS:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_pid_status;
-                       break;
-               case PROC_TID_STAT:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_tid_stat;
-                       break;
-               case PROC_TGID_STAT:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_tgid_stat;
-                       break;
-               case PROC_TID_CMDLINE:
-               case PROC_TGID_CMDLINE:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_pid_cmdline;
-                       break;
-               case PROC_TID_STATM:
-               case PROC_TGID_STATM:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_pid_statm;
-                       break;
-               case PROC_TID_MAPS:
-               case PROC_TGID_MAPS:
-                       inode->i_fop = &proc_maps_operations;
-                       break;
+static int proc_base_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+       struct task_struct *task, struct pid_entry *p)
+{
+       return proc_fill_cache(filp, dirent, filldir, p->name, p->len,
+                               proc_base_instantiate, task, p);
+}
+
+#ifdef CONFIG_TASK_IO_ACCOUNTING
+static int proc_pid_io_accounting(struct task_struct *task, char *buffer)
+{
+       return sprintf(buffer,
+                       "rchar: %llu\n"
+                       "wchar: %llu\n"
+                       "syscr: %llu\n"
+                       "syscw: %llu\n"
+                       "read_bytes: %llu\n"
+                       "write_bytes: %llu\n"
+                       "cancelled_write_bytes: %llu\n",
+                       (unsigned long long)task->rchar,
+                       (unsigned long long)task->wchar,
+                       (unsigned long long)task->syscr,
+                       (unsigned long long)task->syscw,
+                       (unsigned long long)task->ioac.read_bytes,
+                       (unsigned long long)task->ioac.write_bytes,
+                       (unsigned long long)task->ioac.cancelled_write_bytes);
+}
+#endif
+
+/*
+ * Thread groups
+ */
+static struct file_operations proc_task_operations;
+static struct inode_operations proc_task_inode_operations;
+
+extern int proc_pid_vx_info(struct task_struct *, char *);
+extern int proc_pid_nx_info(struct task_struct *, char *);
+
+static struct pid_entry tgid_base_stuff[] = {
+       DIR("task",       S_IRUGO|S_IXUGO, task),
+       DIR("fd",         S_IRUSR|S_IXUSR, fd),
+       INF("environ",    S_IRUSR, pid_environ),
+       INF("auxv",       S_IRUSR, pid_auxv),
+       INF("status",     S_IRUGO, pid_status),
+       INF("cmdline",    S_IRUGO, pid_cmdline),
+       INF("stat",       S_IRUGO, tgid_stat),
+       INF("statm",      S_IRUGO, pid_statm),
+       REG("maps",       S_IRUSR, maps),
 #ifdef CONFIG_NUMA
-               case PROC_TID_NUMA_MAPS:
-               case PROC_TGID_NUMA_MAPS:
-                       inode->i_fop = &proc_numa_maps_operations;
-                       break;
+       REG("numa_maps",  S_IRUGO, numa_maps),
 #endif
-               case PROC_TID_MEM:
-               case PROC_TGID_MEM:
-                       inode->i_fop = &proc_mem_operations;
-                       break;
+       REG("mem",        S_IRUSR|S_IWUSR, mem),
 #ifdef CONFIG_SECCOMP
-               case PROC_TID_SECCOMP:
-               case PROC_TGID_SECCOMP:
-                       inode->i_fop = &proc_seccomp_operations;
-                       break;
-#endif /* CONFIG_SECCOMP */
-               case PROC_TID_MOUNTS:
-               case PROC_TGID_MOUNTS:
-                       inode->i_fop = &proc_mounts_operations;
-                       break;
+       REG("seccomp",    S_IRUSR|S_IWUSR, seccomp),
+#endif
+       LNK("cwd",        cwd),
+       LNK("root",       root),
+       LNK("exe",        exe),
+       REG("mounts",     S_IRUGO, mounts),
+       REG("mountstats", S_IRUSR, mountstats),
 #ifdef CONFIG_MMU
-               case PROC_TID_SMAPS:
-               case PROC_TGID_SMAPS:
-                       inode->i_fop = &proc_smaps_operations;
-                       break;
+       REG("smaps",      S_IRUSR, smaps),
 #endif
-               case PROC_TID_MOUNTSTATS:
-               case PROC_TGID_MOUNTSTATS:
-                       inode->i_fop = &proc_mountstats_operations;
-                       break;
 #ifdef CONFIG_SECURITY
-               case PROC_TID_ATTR:
-                       inode->i_nlink = 2;
-                       inode->i_op = &proc_tid_attr_inode_operations;
-                       inode->i_fop = &proc_tid_attr_operations;
-                       break;
-               case PROC_TGID_ATTR:
-                       inode->i_nlink = 2;
-                       inode->i_op = &proc_tgid_attr_inode_operations;
-                       inode->i_fop = &proc_tgid_attr_operations;
-                       break;
-               case PROC_TID_ATTR_CURRENT:
-               case PROC_TGID_ATTR_CURRENT:
-               case PROC_TID_ATTR_PREV:
-               case PROC_TGID_ATTR_PREV:
-               case PROC_TID_ATTR_EXEC:
-               case PROC_TGID_ATTR_EXEC:
-               case PROC_TID_ATTR_FSCREATE:
-               case PROC_TGID_ATTR_FSCREATE:
-               case PROC_TID_ATTR_KEYCREATE:
-               case PROC_TGID_ATTR_KEYCREATE:
-               case PROC_TID_ATTR_SOCKCREATE:
-               case PROC_TGID_ATTR_SOCKCREATE:
-                       inode->i_fop = &proc_pid_attr_operations;
-                       break;
+       DIR("attr",       S_IRUGO|S_IXUGO, attr_dir),
 #endif
 #ifdef CONFIG_KALLSYMS
-               case PROC_TID_WCHAN:
-               case PROC_TGID_WCHAN:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_pid_wchan;
-                       break;
+       INF("wchan",      S_IRUGO, pid_wchan),
 #endif
 #ifdef CONFIG_SCHEDSTATS
-               case PROC_TID_SCHEDSTAT:
-               case PROC_TGID_SCHEDSTAT:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_pid_schedstat;
-                       break;
+       INF("schedstat",  S_IRUGO, pid_schedstat),
 #endif
 #ifdef CONFIG_CPUSETS
-               case PROC_TID_CPUSET:
-               case PROC_TGID_CPUSET:
-                       inode->i_fop = &proc_cpuset_operations;
-                       break;
+       REG("cpuset",     S_IRUGO, cpuset),
 #endif
-               case PROC_TID_OOM_SCORE:
-               case PROC_TGID_OOM_SCORE:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_oom_score;
-                       break;
-               case PROC_TID_OOM_ADJUST:
-               case PROC_TGID_OOM_ADJUST:
-                       inode->i_fop = &proc_oom_adjust_operations;
-                       break;
+       INF("vinfo",      S_IRUGO, pid_vx_info),
+       INF("ninfo",      S_IRUGO, pid_nx_info),
+       INF("oom_score",  S_IRUGO, oom_score),
+       REG("oom_adj",    S_IRUGO|S_IWUSR, oom_adjust),
 #ifdef CONFIG_AUDITSYSCALL
-               case PROC_TID_LOGINUID:
-               case PROC_TGID_LOGINUID:
-                       inode->i_fop = &proc_loginuid_operations;
-                       break;
+       REG("loginuid",   S_IWUSR|S_IRUGO, loginuid),
+#endif
+#ifdef CONFIG_FAULT_INJECTION
+       REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject),
+#endif
+#ifdef CONFIG_TASK_IO_ACCOUNTING
+       INF("io",       S_IRUGO, pid_io_accounting),
 #endif
-               case PROC_TID_VX_INFO:
-               case PROC_TGID_VX_INFO:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_pid_vx_info;
-                       break;
-               case PROC_TID_IP_INFO:
-               case PROC_TGID_IP_INFO:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_pid_nx_info;
-                       break;
-               default:
-                       printk("procfs: impossible type (%d)",p->type);
-                       iput(inode);
-                       error = ERR_PTR(-EINVAL);
-                       goto out;
-       }
-       dentry->d_op = &pid_dentry_operations;
-       d_add(dentry, inode);
-       /* Close the race of the process dying before we return the dentry */
-       if (pid_revalidate(dentry, NULL))
-               error = NULL;
-out:
-       put_task_struct(task);
-out_no_task:
-       return error;
-}
-
-static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
-       return proc_pident_lookup(dir, dentry, tgid_base_stuff);
-}
-
-static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
-       return proc_pident_lookup(dir, dentry, tid_base_stuff);
-}
-
-static struct file_operations proc_tgid_base_operations = {
-       .read           = generic_read_dir,
-       .readdir        = proc_tgid_base_readdir,
-};
-
-static struct file_operations proc_tid_base_operations = {
-       .read           = generic_read_dir,
-       .readdir        = proc_tid_base_readdir,
-};
-
-static struct inode_operations proc_tgid_base_inode_operations = {
-       .lookup         = proc_tgid_base_lookup,
-       .getattr        = pid_getattr,
-       .setattr        = proc_setattr,
-};
-
-static struct inode_operations proc_tid_base_inode_operations = {
-       .lookup         = proc_tid_base_lookup,
-       .getattr        = pid_getattr,
-       .setattr        = proc_setattr,
 };
 
-#ifdef CONFIG_SECURITY
-static int proc_tgid_attr_readdir(struct file * filp,
-                            void * dirent, filldir_t filldir)
-{
-       return proc_pident_readdir(filp,dirent,filldir,
-                                  tgid_attr_stuff,ARRAY_SIZE(tgid_attr_stuff));
-}
-
-static int proc_tid_attr_readdir(struct file * filp,
+static int proc_tgid_base_readdir(struct file * filp,
                             void * dirent, filldir_t filldir)
 {
        return proc_pident_readdir(filp,dirent,filldir,
-                                  tid_attr_stuff,ARRAY_SIZE(tid_attr_stuff));
-}
-
-static struct file_operations proc_tgid_attr_operations = {
-       .read           = generic_read_dir,
-       .readdir        = proc_tgid_attr_readdir,
-};
-
-static struct file_operations proc_tid_attr_operations = {
-       .read           = generic_read_dir,
-       .readdir        = proc_tid_attr_readdir,
-};
-
-static struct dentry *proc_tgid_attr_lookup(struct inode *dir,
-                               struct dentry *dentry, struct nameidata *nd)
-{
-       return proc_pident_lookup(dir, dentry, tgid_attr_stuff);
-}
-
-static struct dentry *proc_tid_attr_lookup(struct inode *dir,
-                               struct dentry *dentry, struct nameidata *nd)
-{
-       return proc_pident_lookup(dir, dentry, tid_attr_stuff);
-}
-
-static struct inode_operations proc_tgid_attr_inode_operations = {
-       .lookup         = proc_tgid_attr_lookup,
-       .getattr        = pid_getattr,
-       .setattr        = proc_setattr,
-};
-
-static struct inode_operations proc_tid_attr_inode_operations = {
-       .lookup         = proc_tid_attr_lookup,
-       .getattr        = pid_getattr,
-       .setattr        = proc_setattr,
-};
-#endif
-
-/*
- * /proc/self:
- */
-static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
-                             int buflen)
-{
-       char tmp[PROC_NUMBUF];
-       sprintf(tmp, "%d", vx_map_tgid(current->tgid));
-       return vfs_readlink(dentry,buffer,buflen,tmp);
+                                  tgid_base_stuff,ARRAY_SIZE(tgid_base_stuff));
 }
 
-static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
-{
-       char tmp[PROC_NUMBUF];
-       sprintf(tmp, "%d", vx_map_tgid(current->tgid));
-       return ERR_PTR(vfs_follow_link(nd,tmp));
-}      
+static struct file_operations proc_tgid_base_operations = {
+       .read           = generic_read_dir,
+       .readdir        = proc_tgid_base_readdir,
+};
 
-static struct inode_operations proc_self_inode_operations = {
-       .readlink       = proc_self_readlink,
-       .follow_link    = proc_self_follow_link,
+static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
+       return proc_pident_lookup(dir, dentry,
+                                 tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff));
+}
+
+static struct inode_operations proc_tgid_base_inode_operations = {
+       .lookup         = proc_tgid_base_lookup,
+       .getattr        = pid_getattr,
+       .setattr        = proc_setattr,
 };
 
 /**
@@ -2097,54 +2052,24 @@ out:
        return;
 }
 
-/* SMP-safe */
-struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
+static struct dentry *proc_pid_instantiate(struct inode *dir,
+                                          struct dentry * dentry,
+                                          struct task_struct *task, void *ptr)
 {
-       struct dentry *result = ERR_PTR(-ENOENT);
-       struct task_struct *task;
+       struct dentry *error = ERR_PTR(-ENOENT);
        struct inode *inode;
-       struct proc_inode *ei;
-       unsigned tgid;
-
-       if (dentry->d_name.len == 4 && !memcmp(dentry->d_name.name,"self",4)) {
-               inode = new_inode(dir->i_sb);
-               if (!inode)
-                       return ERR_PTR(-ENOMEM);
-               ei = PROC_I(inode);
-               inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-               inode->i_ino = fake_ino(0, PROC_TGID_INO);
-               ei->pde = NULL;
-               inode->i_mode = S_IFLNK|S_IRWXUGO;
-               inode->i_uid = inode->i_gid = 0;
-               inode->i_size = 64;
-               inode->i_op = &proc_self_inode_operations;
-               d_add(dentry, inode);
-               return NULL;
-       }
-       tgid = name_to_int(dentry);
-       if (tgid == ~0U)
-               goto out;
-
-       rcu_read_lock();
-       task = find_proc_task_by_pid(tgid);
-       if (task)
-               get_task_struct(task);
-       rcu_read_unlock();
-       if (!task)
-               goto out;
 
-       inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO);
+       inode = proc_pid_make_inode(dir->i_sb, task);
        if (!inode)
-               goto out_put_task;
+               goto out;
 
        inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
        inode->i_op = &proc_tgid_base_inode_operations;
        inode->i_fop = &proc_tgid_base_operations;
        inode->i_flags|=S_IMMUTABLE;
-#ifdef CONFIG_SECURITY
-       inode->i_nlink = 5;
-#else
        inode->i_nlink = 4;
+#ifdef CONFIG_SECURITY
+       inode->i_nlink += 1;
 #endif
 
        dentry->d_op = &pid_dentry_operations;
@@ -2152,183 +2077,257 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
        if (pid_revalidate(dentry, NULL))
-               result = NULL;
-
-out_put_task:
-       put_task_struct(task);
+               error = NULL;
 out:
-       return result;
+       return error;
 }
 
-/* SMP-safe */
-static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
+struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
 {
        struct dentry *result = ERR_PTR(-ENOENT);
        struct task_struct *task;
-       struct task_struct *leader = get_proc_task(dir);
-       struct inode *inode;
-       unsigned tid;
-
-       if (!leader)
-               goto out_no_task;
+       unsigned tgid;
 
-       tid = name_to_int(dentry);
-       if (tid == ~0U)
+       result = proc_base_lookup(dir, dentry);
+       if (!IS_ERR(result) || PTR_ERR(result) != -ENOENT)
                goto out;
-       if (vx_current_initpid(tid))
+
+       tgid = name_to_int(dentry);
+       if (tgid == ~0U)
                goto out;
 
        rcu_read_lock();
-       task = find_proc_task_by_pid(tid);
+       task = vx_find_proc_task_by_pid(tgid);
        if (task)
                get_task_struct(task);
        rcu_read_unlock();
        if (!task)
                goto out;
-       if (leader->tgid != task->tgid)
-               goto out_drop_task;
-
-       inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_INO);
 
-
-       if (!inode)
-               goto out_drop_task;
-       inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
-       inode->i_op = &proc_tid_base_inode_operations;
-       inode->i_fop = &proc_tid_base_operations;
-       inode->i_flags|=S_IMMUTABLE;
-#ifdef CONFIG_SECURITY
-       inode->i_nlink = 4;
-#else
-       inode->i_nlink = 3;
-#endif
-
-       dentry->d_op = &pid_dentry_operations;
-
-       d_add(dentry, inode);
-       /* Close the race of the process dying before we return the dentry */
-       if (pid_revalidate(dentry, NULL))
-               result = NULL;
-
-out_drop_task:
+       result = proc_pid_instantiate(dir, dentry, task, NULL);
        put_task_struct(task);
 out:
-       put_task_struct(leader);
-out_no_task:
        return result;
 }
 
 /*
- * Find the first tgid to return to user space.
- *
- * Usually this is just whatever follows &init_task, but if the users
- * buffer was too small to hold the full list or there was a seek into
- * the middle of the directory we have more work to do.
- *
- * In the case of a short read we start with find_task_by_pid.
+ * Find the first task with tgid >= tgid
  *
- * In the case of a seek we start with &init_task and walk nr
- * threads past it.
  */
-static struct task_struct *first_tgid(int tgid, unsigned int nr)
+static struct task_struct *next_tgid(unsigned int tgid)
 {
-       struct task_struct *pos;
-       rcu_read_lock();
-       if (tgid && nr) {
-               pos = find_proc_task_by_pid(tgid);
-               if (pos && thread_group_leader(pos))
-                       goto found;
-       }
-       /* If nr exceeds the number of processes get out quickly */
-       pos = NULL;
-       if (nr && nr >= nr_processes())
-               goto done;
+       struct task_struct *task;
+       struct pid *pid;
 
-       /* If we haven't found our starting place yet start with
-        * the init_task and walk nr tasks forward.
-        */
-       for (pos = next_task(&init_task); nr > 0; --nr) {
-               pos = next_task(pos);
-               if (pos == &init_task) {
-                       pos = NULL;
-                       goto done;
-               }
+       rcu_read_lock();
+retry:
+       task = NULL;
+       pid = find_ge_pid(tgid);
+       if (pid) {
+               tgid = pid->nr + 1;
+               task = pid_task(pid, PIDTYPE_PID);
+               /* What we to know is if the pid we have find is the
+                * pid of a thread_group_leader.  Testing for task
+                * being a thread_group_leader is the obvious thing
+                * todo but there is a window when it fails, due to
+                * the pid transfer logic in de_thread.
+                *
+                * So we perform the straight forward test of seeing
+                * if the pid we have found is the pid of a thread
+                * group leader, and don't worry if the task we have
+                * found doesn't happen to be a thread group leader.
+                * As we don't care in the case of readdir.
+                */
+               if (!task || !has_group_leader_pid(task))
+                       goto retry;
+               get_task_struct(task);
        }
-found:
-       get_task_struct(pos);
-done:
        rcu_read_unlock();
-       return pos;
+       return task;
 }
 
-/*
- * Find the next task in the task list.
- * Return NULL if we loop or there is any error.
- *
- * The reference to the input task_struct is released.
- */
-static struct task_struct *next_tgid(struct task_struct *start)
+#define TGID_OFFSET (FIRST_PROCESS_ENTRY + ARRAY_SIZE(proc_base_stuff))
+
+static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+       struct task_struct *task, int tgid)
 {
-       struct task_struct *pos;
-       rcu_read_lock();
-       pos = start;
-       if (pid_alive(start))
-               pos = next_task(start);
-       if (pid_alive(pos) && (pos != &init_task)) {
-               get_task_struct(pos);
-               goto done;
-       }
-       pos = NULL;
-done:
-       rcu_read_unlock();
-       put_task_struct(start);
-       return pos;
+       char name[PROC_NUMBUF];
+       int len = snprintf(name, sizeof(name), "%d", tgid);
+       return proc_fill_cache(filp, dirent, filldir, name, len,
+                               proc_pid_instantiate, task, NULL);
 }
 
 /* for the /proc/ directory itself, after non-process stuff has been done */
 int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
-       char buf[PROC_NUMBUF];
        unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY;
+       struct task_struct *reaper = get_proc_task_real(filp->f_path.dentry->d_inode);
        struct task_struct *task;
        int tgid;
 
-       if (!nr) {
-               ino_t ino = fake_ino(0,PROC_TGID_INO);
-               if (filldir(dirent, "self", 4, filp->f_pos, ino, DT_LNK) < 0)
-                       return 0;
-               filp->f_pos++;
-               nr++;
+       if (!reaper)
+               goto out_no_task;
+
+       for (; nr < ARRAY_SIZE(proc_base_stuff); filp->f_pos++, nr++) {
+               struct pid_entry *p = &proc_base_stuff[nr];
+               if (proc_base_fill_cache(filp, dirent, filldir, reaper, p) < 0)
+                       goto out;
        }
-       nr -= 1;
 
-       /* f_version caches the tgid value that the last readdir call couldn't
-        * return. lseek aka telldir automagically resets f_version to 0.
-        */
-       tgid = filp->f_version;
-       filp->f_version = 0;
-       for (task = first_tgid(tgid, nr);
+       tgid = filp->f_pos - TGID_OFFSET;
+       for (task = next_tgid(tgid);
             task;
-            task = next_tgid(task), filp->f_pos++) {
-               int len;
-               ino_t ino;
-               tgid = vx_map_tgid(task->pid);
-               if (!proc_pid_visible(task, tgid))
+            put_task_struct(task), task = next_tgid(tgid + 1)) {
+               tgid = task->pid;
+               filp->f_pos = tgid + TGID_OFFSET;
+               if (!vx_proc_task_visible(task))
                        continue;
-
-               len = snprintf(buf, sizeof(buf), "%d", tgid);
-               ino = fake_ino(tgid, PROC_TGID_INO);
-               if (filldir(dirent, buf, len, filp->f_pos, ino, DT_DIR) < 0) {
-                       /* returning this tgid failed, save it as the first
-                        * pid for the next readir call */
-                       filp->f_version = tgid;
+               if (proc_pid_fill_cache(filp, dirent, filldir, task, tgid) < 0) {
                        put_task_struct(task);
-                       break;
+                       goto out;
                }
        }
+       filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET;
+out:
+       put_task_struct(reaper);
+out_no_task:
        return 0;
 }
 
+/*
+ * Tasks
+ */
+static struct pid_entry tid_base_stuff[] = {
+       DIR("fd",        S_IRUSR|S_IXUSR, fd),
+       INF("environ",   S_IRUSR, pid_environ),
+       INF("auxv",      S_IRUSR, pid_auxv),
+       INF("status",    S_IRUGO, pid_status),
+       INF("cmdline",   S_IRUGO, pid_cmdline),
+       INF("stat",      S_IRUGO, tid_stat),
+       INF("statm",     S_IRUGO, pid_statm),
+       REG("maps",      S_IRUSR, maps),
+#ifdef CONFIG_NUMA
+       REG("numa_maps", S_IRUGO, numa_maps),
+#endif
+       REG("mem",       S_IRUSR|S_IWUSR, mem),
+#ifdef CONFIG_SECCOMP
+       REG("seccomp",   S_IRUSR|S_IWUSR, seccomp),
+#endif
+       LNK("cwd",       cwd),
+       LNK("root",      root),
+       LNK("exe",       exe),
+       REG("mounts",    S_IRUGO, mounts),
+#ifdef CONFIG_MMU
+       REG("smaps",     S_IRUSR, smaps),
+#endif
+#ifdef CONFIG_SECURITY
+       DIR("attr",      S_IRUGO|S_IXUGO, attr_dir),
+#endif
+#ifdef CONFIG_KALLSYMS
+       INF("wchan",     S_IRUGO, pid_wchan),
+#endif
+#ifdef CONFIG_SCHEDSTATS
+       INF("schedstat", S_IRUGO, pid_schedstat),
+#endif
+#ifdef CONFIG_CPUSETS
+       REG("cpuset",    S_IRUGO, cpuset),
+#endif
+       INF("oom_score", S_IRUGO, oom_score),
+       REG("oom_adj",   S_IRUGO|S_IWUSR, oom_adjust),
+#ifdef CONFIG_AUDITSYSCALL
+       REG("loginuid",  S_IWUSR|S_IRUGO, loginuid),
+#endif
+#ifdef CONFIG_FAULT_INJECTION
+       REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject),
+#endif
+};
+
+static int proc_tid_base_readdir(struct file * filp,
+                            void * dirent, filldir_t filldir)
+{
+       return proc_pident_readdir(filp,dirent,filldir,
+                                  tid_base_stuff,ARRAY_SIZE(tid_base_stuff));
+}
+
+static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
+       return proc_pident_lookup(dir, dentry,
+                                 tid_base_stuff, ARRAY_SIZE(tid_base_stuff));
+}
+
+static struct file_operations proc_tid_base_operations = {
+       .read           = generic_read_dir,
+       .readdir        = proc_tid_base_readdir,
+};
+
+static struct inode_operations proc_tid_base_inode_operations = {
+       .lookup         = proc_tid_base_lookup,
+       .getattr        = pid_getattr,
+       .setattr        = proc_setattr,
+};
+
+static struct dentry *proc_task_instantiate(struct inode *dir,
+       struct dentry *dentry, struct task_struct *task, void *ptr)
+{
+       struct dentry *error = ERR_PTR(-ENOENT);
+       struct inode *inode;
+       inode = proc_pid_make_inode(dir->i_sb, task);
+
+       if (!inode)
+               goto out;
+       inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
+       inode->i_op = &proc_tid_base_inode_operations;
+       inode->i_fop = &proc_tid_base_operations;
+       inode->i_flags|=S_IMMUTABLE;
+       inode->i_nlink = 3;
+#ifdef CONFIG_SECURITY
+       inode->i_nlink += 1;
+#endif
+
+       dentry->d_op = &pid_dentry_operations;
+
+       d_add(dentry, inode);
+       /* Close the race of the process dying before we return the dentry */
+       if (pid_revalidate(dentry, NULL))
+               error = NULL;
+out:
+       return error;
+}
+
+static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
+{
+       struct dentry *result = ERR_PTR(-ENOENT);
+       struct task_struct *task;
+       struct task_struct *leader = get_proc_task(dir);
+       unsigned tid;
+
+       if (!leader)
+               goto out_no_task;
+
+       tid = name_to_int(dentry);
+       if (tid == ~0U)
+               goto out;
+       if (vx_current_initpid(tid))
+               goto out;
+
+       rcu_read_lock();
+       task = vx_find_proc_task_by_pid(tid);
+       if (task)
+               get_task_struct(task);
+       rcu_read_unlock();
+       if (!task)
+               goto out;
+       if (leader->tgid != task->tgid)
+               goto out_drop_task;
+
+       result = proc_task_instantiate(dir, dentry, task, NULL);
+out_drop_task:
+       put_task_struct(task);
+out:
+       put_task_struct(leader);
+out_no_task:
+       return result;
+}
+
 /*
  * Find the first tid of a thread group to return to user space.
  *
@@ -2349,7 +2348,7 @@ static struct task_struct *first_tid(struct task_struct *leader,
        rcu_read_lock();
        /* Attempt to start with the pid of a thread */
        if (tid && (nr > 0)) {
-               pos = find_proc_task_by_pid(tid);
+               pos = find_task_by_pid(tid);
                if (pos && (pos->group_leader == leader))
                        goto found;
        }
@@ -2398,19 +2397,37 @@ static struct task_struct *next_tid(struct task_struct *start)
        return pos;
 }
 
+static int proc_task_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+       struct task_struct *task, int tid)
+{
+       char name[PROC_NUMBUF];
+       int len = snprintf(name, sizeof(name), "%d", tid);
+       return proc_fill_cache(filp, dirent, filldir, name, len,
+                               proc_task_instantiate, task, NULL);
+}
+
 /* for the /proc/TGID/task/ directories */
 static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
-       char buf[PROC_NUMBUF];
-       struct dentry *dentry = filp->f_dentry;
+       struct dentry *dentry = filp->f_path.dentry;
        struct inode *inode = dentry->d_inode;
-       struct task_struct *leader = get_proc_task(inode);
+       struct task_struct *leader = NULL;
        struct task_struct *task;
        int retval = -ENOENT;
        ino_t ino;
        int tid;
        unsigned long pos = filp->f_pos;  /* avoiding "long long" filp->f_pos */
 
+       task = get_proc_task(inode);
+       if (!task)
+               goto out_no_task;
+       rcu_read_lock();
+       if (pid_alive(task)) {
+               leader = task->group_leader;
+               get_task_struct(leader);
+       }
+       rcu_read_unlock();
+       put_task_struct(task);
        if (!leader)
                goto out_no_task;
        retval = 0;
@@ -2438,14 +2455,8 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi
        for (task = first_tid(leader, tid, pos - 2);
             task;
             task = next_tid(task), pos++) {
-               int len;
                tid = vx_map_pid(task->pid);
-               if (!proc_pid_visible(task, tid))
-                       continue;
-
-               len = snprintf(buf, sizeof(buf), "%d", tid);
-               ino = fake_ino(tid, PROC_TID_INO);
-               if (filldir(dirent, buf, len, pos, ino, DT_DIR < 0)) {
+               if (proc_task_fill_cache(filp, dirent, filldir, task, tid) < 0) {
                        /* returning this tgid failed, save it as the first
                         * pid for the next readir call */
                        filp->f_version = tid;
@@ -2475,3 +2486,14 @@ static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct
 
        return 0;
 }
+
+static struct inode_operations proc_task_inode_operations = {
+       .lookup         = proc_task_lookup,
+       .getattr        = proc_task_getattr,
+       .setattr        = proc_setattr,
+};
+
+static struct file_operations proc_task_operations = {
+       .read           = generic_read_dir,
+       .readdir        = proc_task_readdir,
+};