fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / fs / proc / base.c
index 7bd6c8d..3e37b5f 100644 (file)
@@ -49,7 +49,6 @@
 
 #include <asm/uaccess.h>
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/time.h>
 #include <linux/proc_fs.h>
@@ -60,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/vs_cvirt.h>
+#include <linux/nsproxy.h>
+#include <linux/oom.h>
+#include <linux/vs_context.h>
 #include <linux/vs_network.h>
+
 #include "internal.h"
 
-/*
- * 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.
+/* NOTE:
+ *     Implementing inode permission operations in /proc is almost
+ *     certainly an error.  Permission checks need to happen during
+ *     each system call not at open time.  The reason is that most of
+ *     what we wish to check for permissions in /proc varies at runtime.
+ *
+ *     The classic example of a problem is opening file descriptors
+ *     in /proc for a task before it execs a suid executable.
  */
 
-#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_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,
-#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_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,
-#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 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)}
+#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 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_IRUGO),
-#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),
-#ifdef CONFIG_MMU
-       E(PROC_TGID_SMAPS,     "smaps",   S_IFREG|S_IRUGO),
-#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_IRUGO),
-#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_IRUGO),
-#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}
-};
+static struct fs_struct *get_fs_struct(struct task_struct *task)
+{
+       struct fs_struct *fs;
+       task_lock(task);
+       fs = task->fs;
+       if(fs)
+               atomic_inc(&fs->count);
+       task_unlock(task);
+       return fs;
+}
 
-#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),
-       {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),
-       {0,0,NULL,0}
-};
-#endif
+static int get_nr_threads(struct task_struct *tsk)
+{
+       /* Must be called with the rcu_read_lock held */
+       unsigned long flags;
+       int count = 0;
 
-#undef E
+       if (lock_task_sighand(tsk, &flags)) {
+               count = atomic_read(&tsk->signal->count);
+               unlock_task_sighand(tsk, &flags);
+       }
+       return count;
+}
 
-static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+static int __ptrace_may_attach(struct task_struct *task)
 {
-       struct task_struct *task = proc_task(inode);
-       struct files_struct *files;
-       struct file *file;
-       int fd = proc_type(inode) - PROC_TID_FD_DIR;
+       /* 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;
 
-       files = get_files_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;
+       return security_ptrace(current, task);
 }
 
-static struct fs_struct *get_fs_struct(struct task_struct *task)
+int ptrace_may_attach(struct task_struct *task)
 {
-       struct fs_struct *fs;
+       int err;
        task_lock(task);
-       fs = task->fs;
-       if(fs)
-               atomic_inc(&fs->count);
+       err = __ptrace_may_attach(task);
        task_unlock(task);
-       return fs;
+       return !err;
 }
 
+
 static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
-       struct fs_struct *fs = get_fs_struct(proc_task(inode));
+       struct task_struct *task = get_proc_task(inode);
+       struct fs_struct *fs = NULL;
        int result = -ENOENT;
+
+       if (task) {
+               fs = get_fs_struct(task);
+               put_task_struct(task);
+       }
        if (fs) {
                read_lock(&fs->lock);
                *mnt = mntget(fs->pwdmnt);
@@ -351,55 +219,14 @@ static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfs
 
 static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
-       struct fs_struct *fs = get_fs_struct(proc_task(inode));
-       int result = -ENOENT;
-       if (fs) {
-               read_lock(&fs->lock);
-               *mnt = mntget(fs->rootmnt);
-               *dentry = dget(fs->root);
-               read_unlock(&fs->lock);
-               result = 0;
-               put_fs_struct(fs);
-       }
-       return result;
-}
-
-
-/* Same as proc_root_link, but this addionally tries to get fs from other
- * threads in the group */
-static int proc_task_root_link(struct inode *inode, struct dentry **dentry,
-                               struct vfsmount **mnt)
-{
-       struct fs_struct *fs;
+       struct task_struct *task = get_proc_task(inode);
+       struct fs_struct *fs = NULL;
        int result = -ENOENT;
-       struct task_struct *leader = proc_task(inode);
 
-       task_lock(leader);
-       fs = leader->fs;
-       if (fs) {
-               atomic_inc(&fs->count);
-               task_unlock(leader);
-       } else {
-               /* Try to get fs from other threads */
-               task_unlock(leader);
-               read_lock(&tasklist_lock);
-               if (pid_alive(leader)) {
-                       struct task_struct *task = leader;
-
-                       while ((task = next_thread(task)) != leader) {
-                               task_lock(task);
-                               fs = task->fs;
-                               if (fs) {
-                                       atomic_inc(&fs->count);
-                                       task_unlock(task);
-                                       break;
-                               }
-                               task_unlock(task);
-                       }
-               }
-               read_unlock(&tasklist_lock);
+       if (task) {
+               fs = get_fs_struct(task);
+               put_task_struct(task);
        }
-
        if (fs) {
                read_lock(&fs->lock);
                *mnt = mntget(fs->rootmnt);
@@ -411,13 +238,25 @@ static int proc_task_root_link(struct inode *inode, struct dentry **dentry,
        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);
+       if (!mm)
+               return NULL;
+       down_read(&mm->mmap_sem);
+       task_lock(task);
+       if (task->mm != mm)
+               goto out;
+       if (task->mm != current->mm && __ptrace_may_attach(task) < 0)
+               goto out;
+       task_unlock(task);
+       return mm;
+out:
+       task_unlock(task);
+       up_read(&mm->mmap_sem);
+       mmput(mm);
+       return NULL;
+}
 
 static int proc_pid_environ(struct task_struct *task, char * buffer)
 {
@@ -542,68 +381,20 @@ static int proc_oom_score(struct task_struct *task, char *buffer)
 /************************************************************************/
 
 /* permission checks */
-
-/* If the process being read is separated by chroot from the reading process,
- * don't let the reader access the threads.
- */
-static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt)
+static int proc_fd_access_allowed(struct inode *inode)
 {
-       struct dentry *de, *base;
-       struct vfsmount *our_vfsmnt, *mnt;
-       int res = 0;
-
-       /* context admin override */
-       if (capable(CAP_CONTEXT))
-               goto override;
-
-       read_lock(&current->fs->lock);
-       our_vfsmnt = mntget(current->fs->rootmnt);
-       base = dget(current->fs->root);
-       read_unlock(&current->fs->lock);
-
-       spin_lock(&vfsmount_lock);
-       de = root;
-       mnt = vfsmnt;
-
-       while (mnt != our_vfsmnt) {
-               if (mnt == mnt->mnt_parent)
-                       goto out;
-               de = mnt->mnt_mountpoint;
-               mnt = mnt->mnt_parent;
+       struct task_struct *task;
+       int allowed = 0;
+       /* Allow access to a task's file descriptors if it is us or we
+        * may use ptrace attach to the process and find out that
+        * information.
+        */
+       task = get_proc_task(inode);
+       if (task) {
+               allowed = ptrace_may_attach(task);
+               put_task_struct(task);
        }
-
-       if (!is_subdir(de, base))
-               goto out;
-       spin_unlock(&vfsmount_lock);
-
-exit:
-       dput(base);
-       mntput(our_vfsmnt);
-override:
-       dput(root);
-       mntput(vfsmnt);
-       return res;
-out:
-       spin_unlock(&vfsmount_lock);
-       res = -EACCES;
-       goto exit;
-}
-
-static int proc_check_root(struct inode *inode)
-{
-       struct dentry *root;
-       struct vfsmount *vfsmnt;
-
-       if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */
-               return -ENOENT;
-       return proc_check_chroot(root, vfsmnt);
-}
-
-static int proc_permission(struct inode *inode, int mask, struct nameidata *nd)
-{
-       if (generic_permission(inode, mask, NULL) != 0)
-               return -EACCES;
-       return proc_check_root(inode);
+       return allowed;
 }
 
 static int proc_setattr(struct dentry *dentry, struct iattr *attr)
@@ -627,81 +418,6 @@ static struct inode_operations proc_def_inode_operations = {
        .setattr        = proc_setattr,
 };
 
-static int proc_task_permission(struct inode *inode, int mask, struct nameidata *nd)
-{
-       struct dentry *root;
-       struct vfsmount *vfsmnt;
-
-       if (generic_permission(inode, mask, NULL) != 0)
-               return -EACCES;
-
-       if (proc_task_root_link(inode, &root, &vfsmnt))
-               return -ENOENT;
-
-       return proc_check_chroot(root, vfsmnt);
-}
-
-extern struct seq_operations proc_pid_maps_op;
-static int maps_open(struct inode *inode, struct file *file)
-{
-       struct task_struct *task = proc_task(inode);
-       int ret = seq_open(file, &proc_pid_maps_op);
-       if (!ret) {
-               struct seq_file *m = file->private_data;
-               m->private = task;
-       }
-       return ret;
-}
-
-static struct file_operations proc_maps_operations = {
-       .open           = maps_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-
-#ifdef CONFIG_NUMA
-extern struct seq_operations proc_pid_numa_maps_op;
-static int numa_maps_open(struct inode *inode, struct file *file)
-{
-       struct task_struct *task = proc_task(inode);
-       int ret = seq_open(file, &proc_pid_numa_maps_op);
-       if (!ret) {
-               struct seq_file *m = file->private_data;
-               m->private = task;
-       }
-       return ret;
-}
-
-static struct file_operations proc_numa_maps_operations = {
-       .open           = numa_maps_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-#endif
-
-#ifdef CONFIG_MMU
-extern struct seq_operations proc_pid_smaps_op;
-static int smaps_open(struct inode *inode, struct file *file)
-{
-       struct task_struct *task = proc_task(inode);
-       int ret = seq_open(file, &proc_pid_smaps_op);
-       if (!ret) {
-               struct seq_file *m = file->private_data;
-               m->private = task;
-       }
-       return ret;
-}
-
-static struct file_operations proc_smaps_operations = {
-       .open           = smaps_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = seq_release,
-};
-#endif
-
 extern struct seq_operations mounts_op;
 struct proc_mounts {
        struct seq_file m;
@@ -710,31 +426,36 @@ struct proc_mounts {
 
 static int mounts_open(struct inode *inode, struct file *file)
 {
-       struct task_struct *task = proc_task(inode);
-       struct namespace *namespace;
+       struct task_struct *task = get_proc_task(inode);
+       struct mnt_namespace *ns = NULL;
        struct proc_mounts *p;
        int ret = -EINVAL;
 
-       task_lock(task);
-       namespace = task->namespace;
-       if (namespace)
-               get_namespace(namespace);
-       task_unlock(task);
+       if (task) {
+               task_lock(task);
+               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;
 }
@@ -742,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);
@@ -773,26 +494,72 @@ static struct file_operations proc_mounts_operations = {
        .poll           = mounts_poll,
 };
 
+extern struct seq_operations mountstats_op;
+static int mountstats_open(struct inode *inode, struct file *file)
+{
+       int ret = seq_open(file, &mountstats_op);
+
+       if (!ret) {
+               struct seq_file *m = file->private_data;
+               struct mnt_namespace *mnt_ns = NULL;
+               struct task_struct *task = get_proc_task(inode);
+
+               if (task) {
+                       task_lock(task);
+                       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 (mnt_ns)
+                       m->private = mnt_ns;
+               else {
+                       seq_release(inode, file);
+                       ret = -EINVAL;
+               }
+       }
+       return ret;
+}
+
+static struct file_operations proc_mountstats_operations = {
+       .open           = mountstats_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = mounts_release,
+};
+
 #define PROC_BLOCK_SIZE        (3*1024)                /* 4K page size but our output routines use some slack for overruns */
 
 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 = proc_task(inode);
+       struct task_struct *task = get_proc_task(inode);
+
+       length = -ESRCH;
+       if (!task)
+               goto out_no_task;
 
        if (count > PROC_BLOCK_SIZE)
                count = PROC_BLOCK_SIZE;
+
+       length = -ENOMEM;
        if (!(page = __get_free_page(GFP_KERNEL)))
-               return -ENOMEM;
+               goto out;
 
        length = PROC_I(inode)->op.proc_read(task, (char*)page);
 
        if (length >= 0)
                length = simple_read_from_buffer(buf, count, ppos, (char *)page, length);
        free_page(page);
+out:
+       put_task_struct(task);
+out_no_task:
        return length;
 }
 
@@ -809,13 +576,17 @@ 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 = 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;
        struct mm_struct *mm;
 
-       if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
+       if (!task)
+               goto out_no_task;
+
+       if (!tracehook_allow_access_process_vm(task)
+           || !ptrace_may_attach(task))
                goto out;
 
        ret = -ENOMEM;
@@ -841,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;
@@ -864,6 +636,8 @@ out_put:
 out_free:
        free_page((unsigned long) page);
 out:
+       put_task_struct(task);
+out_no_task:
        return ret;
 }
 
@@ -874,18 +648,25 @@ out:
 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 = proc_task(file->f_dentry->d_inode);
+       struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
        unsigned long dst = *ppos;
 
-       if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
-               return -ESRCH;
+       copied = -ESRCH;
+       if (!task)
+               goto out_no_task;
+
+       if (!tracehook_allow_access_process_vm(task)
+           || !ptrace_may_attach(task))
+               goto out;
 
+       copied = -ENOMEM;
        page = (char *)__get_free_page(GFP_USER);
        if (!page)
-               return -ENOMEM;
+               goto out;
 
+       copied = 0;
        while (count > 0) {
                int this_len, retval;
 
@@ -907,6 +688,9 @@ static ssize_t mem_write(struct file * file, const char * buf,
        }
        *ppos = dst;
        free_page((unsigned long) page);
+out:
+       put_task_struct(task);
+out_no_task:
        return copied;
 }
 #endif
@@ -937,13 +721,18 @@ 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 = proc_task(file->f_dentry->d_inode);
-       char buffer[8];
+       struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
+       char buffer[PROC_NUMBUF];
        size_t len;
-       int oom_adjust = task->oomkilladj;
+       int oom_adjust;
        loff_t __ppos = *ppos;
 
-       len = sprintf(buffer, "%i\n", oom_adjust);
+       if (!task)
+               return -ESRCH;
+       oom_adjust = task->oomkilladj;
+       put_task_struct(task);
+
+       len = snprintf(buffer, sizeof(buffer), "%i\n", oom_adjust);
        if (__ppos >= len)
                return 0;
        if (count > len-__ppos)
@@ -957,23 +746,30 @@ static ssize_t oom_adjust_read(struct file *file, char __user *buf,
 static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
                                size_t count, loff_t *ppos)
 {
-       struct task_struct *task = proc_task(file->f_dentry->d_inode);
-       char buffer[8], *end;
+       struct task_struct *task;
+       char buffer[PROC_NUMBUF], *end;
        int oom_adjust;
 
-       if (!capable(CAP_SYS_RESOURCE))
-               return -EPERM;
-       memset(buffer, 0, 8);
-       if (count > 6)
-               count = 6;
+       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_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)
                return -EIO;
        return end - buffer;
@@ -984,43 +780,40 @@ static struct file_operations proc_oom_adjust_operations = {
        .write          = oom_adjust_write,
 };
 
-static struct inode_operations proc_mem_inode_operations = {
-       .permission     = proc_permission,
-       .setattr        = proc_setattr,
-};
-
 #ifdef CONFIG_AUDITSYSCALL
 #define TMPBUFLEN 21
 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 task_struct *task = proc_task(inode);
+       struct inode * inode = file->f_path.dentry->d_inode;
+       struct task_struct *task = get_proc_task(inode);
        ssize_t length;
        char tmpbuf[TMPBUFLEN];
 
+       if (!task)
+               return -ESRCH;
        length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
                                audit_get_loginuid(task->audit_context));
+       put_task_struct(task);
        return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
 }
 
 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;
-       struct task_struct *task = proc_task(inode);
        uid_t loginuid;
 
        if (!capable(CAP_AUDIT_CONTROL))
                return -EPERM;
 
-       if (current != task)
+       if (current != pid_task(proc_pid(inode), PIDTYPE_PID))
                return -EPERM;
 
-       if (count > PAGE_SIZE)
-               count = PAGE_SIZE;
+       if (count >= PAGE_SIZE)
+               count = PAGE_SIZE - 1;
 
        if (*ppos != 0) {
                /* No partial writes. */
@@ -1033,13 +826,14 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
        if (copy_from_user(page, buf, count))
                goto out_free_page;
 
+       page[count] = '\0';
        loginuid = simple_strtoul(page, &tmp, 10);
        if (tmp == page) {
                length = -EINVAL;
                goto out_free_page;
 
        }
-       length = audit_set_loginuid(task, loginuid);
+       length = audit_set_loginuid(current, loginuid);
        if (likely(length == 0))
                length = count;
 
@@ -1058,13 +852,16 @@ static struct file_operations proc_loginuid_operations = {
 static ssize_t seccomp_read(struct file *file, char __user *buf,
                            size_t count, loff_t *ppos)
 {
-       struct task_struct *tsk = proc_task(file->f_dentry->d_inode);
+       struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode);
        char __buf[20];
        loff_t __ppos = *ppos;
        size_t len;
 
+       if (!tsk)
+               return -ESRCH;
        /* no need to print the trailing zero, so use only len */
        len = sprintf(__buf, "%u\n", tsk->seccomp.mode);
+       put_task_struct(tsk);
        if (__ppos >= len)
                return 0;
        if (count > len - __ppos)
@@ -1078,29 +875,43 @@ static ssize_t seccomp_read(struct file *file, char __user *buf,
 static ssize_t seccomp_write(struct file *file, const char __user *buf,
                             size_t count, loff_t *ppos)
 {
-       struct task_struct *tsk = proc_task(file->f_dentry->d_inode);
+       struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode);
        char __buf[20], *end;
        unsigned int seccomp_mode;
+       ssize_t result;
+
+       result = -ESRCH;
+       if (!tsk)
+               goto out_no_task;
 
        /* can set it only once to be even more secure */
+       result = -EPERM;
        if (unlikely(tsk->seccomp.mode))
-               return -EPERM;
+               goto out;
 
+       result = -EFAULT;
        memset(__buf, 0, sizeof(__buf));
        count = min(count, sizeof(__buf) - 1);
        if (copy_from_user(__buf, buf, count))
-               return -EFAULT;
+               goto out;
+
        seccomp_mode = simple_strtoul(__buf, &end, 0);
        if (*end == '\n')
                end++;
+       result = -EINVAL;
        if (seccomp_mode && seccomp_mode <= NR_SECCOMP_MODES) {
                tsk->seccomp.mode = seccomp_mode;
                set_tsk_thread_flag(tsk, TIF_SECCOMP);
        } else
-               return -EINVAL;
+               goto out;
+       result = -EIO;
        if (unlikely(!(end - __buf)))
-               return -EIO;
-       return end - __buf;
+               goto out;
+       result = end - __buf;
+out:
+       put_task_struct(tsk);
+out_no_task:
+       return result;
 }
 
 static struct file_operations proc_seccomp_operations = {
@@ -1109,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;
@@ -1117,10 +987,8 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
        /* We don't need a base pointer in the /proc filesystem */
        path_release(nd);
 
-       if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE))
-               goto out;
-       error = proc_check_root(inode);
-       if (error)
+       /* Are we allowed to snoop on the tasks file descriptors? */
+       if (!proc_fd_access_allowed(inode))
                goto out;
 
        error = PROC_I(inode)->op.proc_get_link(inode, &nd->dentry, &nd->mnt);
@@ -1162,12 +1030,8 @@ static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int b
        struct dentry *de;
        struct vfsmount *mnt = NULL;
 
-       lock_kernel();
-
-       if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE))
-               goto out;
-       error = proc_check_root(inode);
-       if (error)
+       /* Are we allowed to snoop on the tasks file descriptors? */
+       if (!proc_fd_access_allowed(inode))
                goto out;
 
        error = PROC_I(inode)->op.proc_get_link(inode, &de, &mnt);
@@ -1178,7 +1042,6 @@ static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int b
        dput(de);
        mntput(mnt);
 out:
-       unlock_kernel();
        return error;
 }
 
@@ -1188,149 +1051,6 @@ static struct inode_operations proc_pid_link_inode_operations = {
        .setattr        = proc_setattr,
 };
 
-#define NUMBUF 10
-
-static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
-{
-       struct inode *inode = filp->f_dentry->d_inode;
-       struct task_struct *p = proc_task(inode);
-       unsigned int fd, tid, ino;
-       int retval;
-       char buf[NUMBUF];
-       struct files_struct * files;
-       struct fdtable *fdt;
-
-       retval = -ENOENT;
-       if (!pid_alive(p))
-               goto out;
-       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 = fake_ino(tid, PROC_TID_INO);
-                       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();
-
-                               j = NUMBUF;
-                               i = fd;
-                               do {
-                                       j--;
-                                       buf[j] = '0' + (i % 10);
-                                       i /= 10;
-                               } while (i);
-
-                               ino = fake_ino(tid, PROC_TID_FD_DIR + fd);
-                               if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino, DT_LNK) < 0) {
-                                       rcu_read_lock();
-                                       break;
-                               }
-                               rcu_read_lock();
-                       }
-                       rcu_read_unlock();
-                       put_files_struct(files);
-       }
-out:
-       return retval;
-}
-
-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_dentry;
-       struct inode *inode = dentry->d_inode;
-       struct pid_entry *p;
-       ino_t ino;
-       int ret, hide;
-
-       ret = -ENOENT;
-       if (!pid_alive(proc_task(inode)))
-               goto out;
-
-       ret = 0;
-       pid = proc_task(inode)->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;
-               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 */
 
@@ -1350,51 +1070,68 @@ static int task_dumpable(struct task_struct *task)
 }
 
 
-static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task, int ino)
+static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task)
 {
        struct inode * inode;
        struct proc_inode *ei;
 
        /* We need a new inode */
-       
+
        inode = new_inode(sb);
        if (!inode)
                goto out;
 
        /* Common stuff */
        ei = PROC_I(inode);
-       ei->task = NULL;
        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;
 
-       if (!pid_alive(task))
-               goto out_unlock;
-
        /*
         * grab the reference to task.
         */
-       get_task_struct(task);
-       ei->task = task;
-       ei->type = ino;
+       ei->pid = get_task_pid(task, PIDTYPE_PID);
+       if (!ei->pid)
+               goto out_unlock;
+
        inode->i_uid = 0;
        inode->i_gid = 0;
-       if (ino == PROC_TGID_INO || ino == PROC_TID_INO || task_dumpable(task)) {
+       if (task_dumpable(task)) {
                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:
        return inode;
 
 out_unlock:
-       ei->pde = NULL;
        iput(inode);
        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 */
 
 /*
@@ -1404,18 +1141,21 @@ out_unlock:
  *
  * Rewrite the inode's ownerships here because the owning task may have
  * performed a setuid(), etc.
+ *
+ * Before the /proc/pid/status file was created the only way to read
+ * the effective uid of a /process was to stat /proc/pid.  Reading
+ * /proc/pid/status is slow enough that procps and other packages
+ * kept stating /proc/pid.  To keep the rules in /proc simple I have
+ * made this apply to all per process world readable and executable
+ * directories.
  */
 static int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
 {
        struct inode *inode = dentry->d_inode;
-       struct task_struct *task = proc_task(inode);
-
-       if (!vx_check(vx_task_xid(task), VX_IDENT))
-               goto out_drop;
-       /* discard wrong fakeinit */
-
-       if (pid_alive(task)) {
-               if (proc_type(inode) == PROC_TGID_INO || proc_type(inode) == PROC_TID_INO || task_dumpable(task)) {
+       struct task_struct *task = get_proc_task(inode);
+       if (task) {
+               if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
+                   task_dumpable(task)) {
                        inode->i_uid = task->euid;
                        inode->i_gid = task->egid;
                } else {
@@ -1424,94 +1164,96 @@ static int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
                }
                inode->i_mode &= ~(S_ISUID | S_ISGID);
                security_task_to_inode(task, inode);
+               put_task_struct(task);
                return 1;
        }
-out_drop:
-       d_drop(dentry);
-       return 0;
-}
-
-static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
-{
-       struct inode *inode = dentry->d_inode;
-       struct task_struct *task = proc_task(inode);
-       int fd = proc_type(inode) - PROC_TID_FD_DIR;
-       struct files_struct *files;
-
-       files = get_files_struct(task);
-       if (files) {
-               rcu_read_lock();
-               if (fcheck_files(files, fd)) {
-                       rcu_read_unlock();
-                       put_files_struct(files);
-                       if (task_dumpable(task)) {
-                               inode->i_uid = task->euid;
-                               inode->i_gid = task->egid;
-                       } else {
-                               inode->i_uid = 0;
-                               inode->i_gid = 0;
-                       }
-                       inode->i_mode &= ~(S_ISUID | S_ISGID);
-                       security_task_to_inode(task, inode);
-                       return 1;
-               }
-               rcu_read_unlock();
-               put_files_struct(files);
-       }
        d_drop(dentry);
        return 0;
 }
 
-static void pid_base_iput(struct dentry *dentry, struct inode *inode)
-{
-       struct task_struct *task = proc_task(inode);
-       spin_lock(&task->proc_lock);
-       if (task->proc_dentry == dentry)
-               task->proc_dentry = NULL;
-       spin_unlock(&task->proc_lock);
-       iput(inode);
-}
-
 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 !pid_alive(proc_task(dentry->d_inode));
+       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,
 };
 
-static struct dentry_operations pid_base_dentry_operations =
-{
-       .d_revalidate   = pid_revalidate,
-       .d_iput         = pid_base_iput,
-       .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;
+typedef struct dentry *instantiate_t(struct inode *, struct dentry *, struct task_struct *, void *);
 
-       if (len > 1 && *name == '0')
-               goto out;
-       while (len-- > 0) {
-               unsigned c = *name++ - '0';
+/*
+ * 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)
@@ -1524,28 +1266,96 @@ out:
        return ~0U;
 }
 
-/* SMP-safe */
-static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
 {
-       struct task_struct *task = proc_task(dir);
-       unsigned fd = name_to_int(dentry);
-       struct file * file;
-       struct files_struct * files;
-       struct inode *inode;
-       struct proc_inode *ei;
+       struct task_struct *task = get_proc_task(inode);
+       struct files_struct *files = NULL;
+       struct file *file;
+       int fd = proc_fd(inode);
 
-       if (fd == ~0U)
-               goto out;
-       if (!pid_alive(task))
-               goto out;
+       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_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);
+       }
+       return -ENOENT;
+}
+
+static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+       struct inode *inode = dentry->d_inode;
+       struct task_struct *task = get_proc_task(inode);
+       int fd = proc_fd(inode);
+       struct files_struct *files;
+
+       if (task) {
+               files = get_files_struct(task);
+               if (files) {
+                       rcu_read_lock();
+                       if (fcheck_files(files, fd)) {
+                               rcu_read_unlock();
+                               put_files_struct(files);
+                               if (task_dumpable(task)) {
+                                       inode->i_uid = task->euid;
+                                       inode->i_gid = task->egid;
+                               } else {
+                                       inode->i_uid = 0;
+                                       inode->i_gid = 0;
+                               }
+                               inode->i_mode &= ~(S_ISUID | S_ISGID);
+                               security_task_to_inode(task, inode);
+                               put_task_struct(task);
+                               return 1;
+                       }
+                       rcu_read_unlock();
+                       put_files_struct(files);
+               }
+               put_task_struct(task);
+       }
+       d_drop(dentry);
+       return 0;
+}
+
+static struct dentry_operations tid_fd_dentry_operations =
+{
+       .d_revalidate   = tid_fd_revalidate,
+       .d_delete       = pid_delete_dentry,
+};
+
+static struct dentry *proc_fd_instantiate(struct inode *dir,
+       struct dentry *dentry, struct task_struct *task, void *ptr)
+{
+       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;
 
        /*
@@ -1555,352 +1365,608 @@ 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;
        dentry->d_op = &tid_fd_dentry_operations;
        d_add(dentry, inode);
-       return NULL;
+       /* Close the race of the process dying before we return the dentry */
+       if (tid_fd_revalidate(dentry, NULL))
+               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 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:
-       return ERR_PTR(-ENOENT);
+       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_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_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..
  */
 static struct inode_operations proc_fd_inode_operations = {
        .lookup         = proc_lookupfd,
-       .permission     = proc_permission,
        .setattr        = proc_setattr,
 };
 
-static struct inode_operations proc_task_inode_operations = {
-       .lookup         = proc_task_lookup,
-       .permission     = proc_task_permission,
-       .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 = proc_task(inode);
+       struct task_struct *task = get_proc_task(inode);
+
+       length = -ESRCH;
+       if (!task)
+               goto out_no_task;
 
        if (count > PAGE_SIZE)
                count = PAGE_SIZE;
+       length = -ENOMEM;
        if (!(page = __get_free_page(GFP_KERNEL)))
-               return -ENOMEM;
+               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);
        free_page(page);
+out:
+       put_task_struct(task);
+out_no_task:
        return length;
 }
 
 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 task_struct *task = proc_task(inode); 
-
-       if (count > PAGE_SIZE) 
-               count = PAGE_SIZE; 
-       if (*ppos != 0) {
-               /* No partial writes. */
-               return -EINVAL;
-       }
-       page = (char*)__get_free_page(GFP_USER); 
-       if (!page) 
-               return -ENOMEM;
-       length = -EFAULT; 
-       if (copy_from_user(page, buf, count)) 
+{
+       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;
+
+       /* No partial writes. */
+       length = -EINVAL;
+       if (*ppos != 0)
+               goto out;
+
+       length = -ENOMEM;
+       page = (char*)__get_free_page(GFP_USER);
+       if (!page)
                goto out;
 
-       length = security_setprocattr(task, 
-                                     (char*)file->f_dentry->d_name.name, 
+       length = -EFAULT;
+       if (copy_from_user(page, buf, count))
+               goto out_free;
+
+       length = security_setprocattr(task,
+                                     (char*)file->f_path.dentry->d_name.name,
                                      (void*)page, count);
-out:
+out_free:
        free_page((unsigned long) page);
+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);
+}
 
-static int get_tid_list(int index, unsigned int *tids, struct inode *dir);
+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));
+}
 
-/* SMP-safe */
-static struct dentry *proc_pident_lookup(struct inode *dir, 
-                                        struct dentry *dentry,
-                                        struct pid_entry *ents)
+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;
-       int error;
-       struct task_struct *task = proc_task(dir);
-       struct pid_entry *p;
        struct proc_inode *ei;
+       struct dentry *error = ERR_PTR(-EINVAL);
 
-       error = -ENOENT;
-       inode = NULL;
-
-       if (!pid_alive(task))
+       /* Allocate the inode */
+       error = ERR_PTR(-ENOMEM);
+       inode = new_inode(dir->i_sb);
+       if (!inode)
                goto out;
 
-       for (p = ents; p->name; p++) {
+       /* 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);
+
+       if (!task)
+               goto out_no_task;
+
+       /* 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 = -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 + get_tid_list(2, NULL, dir);
-                       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_op = &proc_mem_inode_operations;
-                       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
 #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:
-                       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
-               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);
-                       error = -EINVAL;
-                       goto out_put;
-       }
-       dentry->d_op = &pid_dentry_operations;
-       d_add(dentry, inode);
-       return NULL;
-
-out_put:
-       iput(inode);
-out:
-       return ERR_PTR(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);
-}
+#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
+};
 
-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 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 struct file_operations proc_tgid_base_operations = {
@@ -1908,451 +1974,462 @@ static struct file_operations proc_tgid_base_operations = {
        .readdir        = proc_tgid_base_readdir,
 };
 
-static struct file_operations proc_tid_base_operations = {
-       .read           = generic_read_dir,
-       .readdir        = proc_tid_base_readdir,
-};
+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,
 };
 
-static struct inode_operations proc_tid_base_inode_operations = {
-       .lookup         = proc_tid_base_lookup,
-       .setattr        = proc_setattr,
-};
-
-#ifdef CONFIG_SECURITY
-static int proc_tgid_attr_readdir(struct file * filp,
-                            void * dirent, filldir_t filldir)
+/**
+ * proc_flush_task -  Remove dcache entries for @task from the /proc dcache.
+ *
+ * @task: task that should be flushed.
+ *
+ * Looks in the dcache for
+ * /proc/@pid
+ * /proc/@tgid/task/@pid
+ * if either directory is present flushes it and all of it'ts children
+ * from the dcache.
+ *
+ * It is safe and reasonable to cache /proc entries for a task until
+ * that task exits.  After that they just clog up the dcache with
+ * useless entries, possibly causing useful dcache entries to be
+ * flushed instead.  This routine is proved to flush those useless
+ * dcache entries at process exit time.
+ *
+ * NOTE: This routine is just an optimization so it does not guarantee
+ *       that no dcache entries will exist at process exit time it
+ *       just makes it very unlikely that any will persist.
+ */
+void proc_flush_task(struct task_struct *task)
 {
-       return proc_pident_readdir(filp,dirent,filldir,
-                                  tgid_attr_stuff,ARRAY_SIZE(tgid_attr_stuff));
+       struct dentry *dentry, *leader, *dir;
+       char buf[PROC_NUMBUF];
+       struct qstr name;
+
+       name.name = buf;
+       name.len = snprintf(buf, sizeof(buf), "%d", task->pid);
+       dentry = d_hash_and_lookup(proc_mnt->mnt_root, &name);
+       if (dentry) {
+               shrink_dcache_parent(dentry);
+               d_drop(dentry);
+               dput(dentry);
+       }
+
+       if (thread_group_leader(task))
+               goto out;
+
+       name.name = buf;
+       name.len = snprintf(buf, sizeof(buf), "%d", task->tgid);
+       leader = d_hash_and_lookup(proc_mnt->mnt_root, &name);
+       if (!leader)
+               goto out;
+
+       name.name = "task";
+       name.len = strlen(name.name);
+       dir = d_hash_and_lookup(leader, &name);
+       if (!dir)
+               goto out_put_leader;
+
+       name.name = buf;
+       name.len = snprintf(buf, sizeof(buf), "%d", task->pid);
+       dentry = d_hash_and_lookup(dir, &name);
+       if (dentry) {
+               shrink_dcache_parent(dentry);
+               d_drop(dentry);
+               dput(dentry);
+       }
+
+       dput(dir);
+out_put_leader:
+       dput(leader);
+out:
+       return;
 }
 
-static int proc_tid_attr_readdir(struct file * filp,
-                            void * dirent, filldir_t filldir)
+static struct dentry *proc_pid_instantiate(struct inode *dir,
+                                          struct dentry * dentry,
+                                          struct task_struct *task, void *ptr)
 {
-       return proc_pident_readdir(filp,dirent,filldir,
-                                  tid_attr_stuff,ARRAY_SIZE(tid_attr_stuff));
-}
+       struct dentry *error = ERR_PTR(-ENOENT);
+       struct inode *inode;
 
-static struct file_operations proc_tgid_attr_operations = {
-       .read           = generic_read_dir,
-       .readdir        = proc_tgid_attr_readdir,
-};
+       inode = proc_pid_make_inode(dir->i_sb, task);
+       if (!inode)
+               goto out;
 
-static struct file_operations proc_tid_attr_operations = {
-       .read           = generic_read_dir,
-       .readdir        = proc_tid_attr_readdir,
-};
+       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;
+       inode->i_nlink = 4;
+#ifdef CONFIG_SECURITY
+       inode->i_nlink += 1;
+#endif
 
-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);
+       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_tid_attr_lookup(struct inode *dir,
-                               struct dentry *dentry, struct nameidata *nd)
+struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
 {
-       return proc_pident_lookup(dir, dentry, tid_attr_stuff);
-}
+       struct dentry *result = ERR_PTR(-ENOENT);
+       struct task_struct *task;
+       unsigned tgid;
 
-static struct inode_operations proc_tgid_attr_inode_operations = {
-       .lookup         = proc_tgid_attr_lookup,
-       .setattr        = proc_setattr,
-};
+       result = proc_base_lookup(dir, dentry);
+       if (!IS_ERR(result) || PTR_ERR(result) != -ENOENT)
+               goto out;
 
-static struct inode_operations proc_tid_attr_inode_operations = {
-       .lookup         = proc_tid_attr_lookup,
-       .setattr        = proc_setattr,
-};
-#endif
+       tgid = name_to_int(dentry);
+       if (tgid == ~0U)
+               goto out;
+
+       rcu_read_lock();
+       task = vx_find_proc_task_by_pid(tgid);
+       if (task)
+               get_task_struct(task);
+       rcu_read_unlock();
+       if (!task)
+               goto out;
+
+       result = proc_pid_instantiate(dir, dentry, task, NULL);
+       put_task_struct(task);
+out:
+       return result;
+}
 
 /*
- * /proc/self:
+ * Find the first task with tgid >= tgid
+ *
  */
-static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
-                             int buflen)
+static struct task_struct *next_tgid(unsigned int tgid)
 {
-       char tmp[30];
-       sprintf(tmp, "%d", vx_map_tgid(current->tgid));
-       return vfs_readlink(dentry,buffer,buflen,tmp);
+       struct task_struct *task;
+       struct pid *pid;
+
+       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);
+       }
+       rcu_read_unlock();
+       return task;
 }
 
-static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
-{
-       char tmp[30];
-       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,
-       .setattr        = proc_setattr,
-};
+#define TGID_OFFSET (FIRST_PROCESS_ENTRY + ARRAY_SIZE(proc_base_stuff))
 
-/**
- * proc_pid_unhash -  Unhash /proc/@pid entry from the dcache.
- * @p: task that should be flushed.
- *
- * Drops the /proc/@pid dcache entry from the hash chains.
- *
- * Dropping /proc/@pid entries and detach_pid must be synchroneous,
- * otherwise e.g. /proc/@pid/exe might point to the wrong executable,
- * if the pid value is immediately reused. This is enforced by
- * - caller must acquire spin_lock(p->proc_lock)
- * - must be called before detach_pid()
- * - proc_pid_lookup acquires proc_lock, and checks that
- *   the target is not dead by looking at the attach count
- *   of PIDTYPE_PID.
- */
+static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+       struct task_struct *task, int tgid)
+{
+       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);
+}
 
-struct dentry *proc_pid_unhash(struct task_struct *p)
+/* for the /proc/ directory itself, after non-process stuff has been done */
+int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
-       struct dentry *proc_dentry;
+       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;
 
-       proc_dentry = p->proc_dentry;
-       if (proc_dentry != NULL) {
+       if (!reaper)
+               goto out_no_task;
 
-               spin_lock(&dcache_lock);
-               spin_lock(&proc_dentry->d_lock);
-               if (!d_unhashed(proc_dentry)) {
-                       dget_locked(proc_dentry);
-                       __d_drop(proc_dentry);
-                       spin_unlock(&proc_dentry->d_lock);
-               } else {
-                       spin_unlock(&proc_dentry->d_lock);
-                       proc_dentry = NULL;
+       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;
+       }
+
+       tgid = filp->f_pos - TGID_OFFSET;
+       for (task = next_tgid(tgid);
+            task;
+            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;
+               if (proc_pid_fill_cache(filp, dirent, filldir, task, tgid) < 0) {
+                       put_task_struct(task);
+                       goto out;
                }
-               spin_unlock(&dcache_lock);
        }
-       return proc_dentry;
+       filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET;
+out:
+       put_task_struct(reaper);
+out_no_task:
+       return 0;
 }
 
-/**
- * proc_pid_flush - recover memory used by stale /proc/@pid/x entries
- * @proc_dentry: directoy to prune.
- *
- * Shrink the /proc directory that was used by the just killed thread.
+/*
+ * Tasks
  */
-       
-void proc_pid_flush(struct dentry *proc_dentry)
+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)
 {
-       might_sleep();
-       if(proc_dentry != NULL) {
-               shrink_dcache_parent(proc_dentry);
-               dput(proc_dentry);
-       }
+       return proc_pident_readdir(filp,dirent,filldir,
+                                  tid_base_stuff,ARRAY_SIZE(tid_base_stuff));
 }
 
-#define VXF_FAKE_INIT  (VXF_INFO_INIT|VXF_STATE_INIT)
-
-static inline int proc_pid_visible(struct task_struct *task, int pid)
-{
-       if ((pid == 1) &&
-               !vx_flags(VXF_FAKE_INIT, VXF_FAKE_INIT))
-               goto visible;
-       if (vx_check(vx_task_xid(task), VX_WATCH|VX_IDENT))
-               goto visible;
-       return 0;
-visible:
-       return 1;
+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));
 }
 
-/* SMP-safe */
-struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
-{
-       struct task_struct *task;
-       struct inode *inode;
-       struct proc_inode *ei;
-       unsigned tgid;
-       int died;
-
-       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;
+static struct file_operations proc_tid_base_operations = {
+       .read           = generic_read_dir,
+       .readdir        = proc_tid_base_readdir,
+};
 
-       read_lock(&tasklist_lock);
-       task = find_task_by_pid(tgid);
-       if (task)
-               get_task_struct(task);
-       read_unlock(&tasklist_lock);
-       if (!task)
-               goto out;
+static struct inode_operations proc_tid_base_inode_operations = {
+       .lookup         = proc_tid_base_lookup,
+       .getattr        = pid_getattr,
+       .setattr        = proc_setattr,
+};
 
-       /* check for context visibility */
-       if (!proc_pid_visible(task, tgid))
-               goto out_drop_task;
+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);
 
-       inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO);
        if (!inode)
-               goto out_drop_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_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 = 5;
-#else
-       inode->i_nlink = 4;
+       inode->i_nlink += 1;
 #endif
 
-       dentry->d_op = &pid_base_dentry_operations;
+       dentry->d_op = &pid_dentry_operations;
 
-       died = 0;
        d_add(dentry, inode);
-       spin_lock(&task->proc_lock);
-       task->proc_dentry = dentry;
-       if (!pid_alive(task)) {
-               dentry = proc_pid_unhash(task);
-               died = 1;
-       }
-       spin_unlock(&task->proc_lock);
-
-       put_task_struct(task);
-       if (died) {
-               proc_pid_flush(dentry);
-               goto out;
-       }
-       return NULL;
-out_drop_task:
-       put_task_struct(task);
+       /* Close the race of the process dying before we return the dentry */
+       if (pid_revalidate(dentry, NULL))
+               error = NULL;
 out:
-       return ERR_PTR(-ENOENT);
+       return error;
 }
 
-/* SMP-safe */
 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 = proc_task(dir);
-       struct inode *inode;
+       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;
 
-       read_lock(&tasklist_lock);
-       task = find_task_by_pid(tid);
+       rcu_read_lock();
+       task = vx_find_proc_task_by_pid(tid);
        if (task)
                get_task_struct(task);
-       read_unlock(&tasklist_lock);
+       rcu_read_unlock();
        if (!task)
                goto out;
        if (leader->tgid != task->tgid)
                goto out_drop_task;
 
-       /* check for context visibility */
-       if (!proc_pid_visible(task, tid))
-               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_base_dentry_operations;
-
-       d_add(dentry, inode);
-
-       put_task_struct(task);
-       return NULL;
+       result = proc_task_instantiate(dir, dentry, task, NULL);
 out_drop_task:
        put_task_struct(task);
 out:
-       return ERR_PTR(-ENOENT);
+       put_task_struct(leader);
+out_no_task:
+       return result;
 }
 
-#define PROC_NUMBUF 10
-#define PROC_MAXPIDS 20
-
 /*
- * Get a few tgid's to return for filldir - we need to hold the
- * tasklist lock while doing this, and we must release it before
- * we actually do the filldir itself, so we use a temp buffer..
+ * Find the first tid of a thread group to return to user space.
+ *
+ * Usually this is just the thread group leader, but if the users
+ * buffer was too small or there was a seek into the middle of the
+ * directory we have more work todo.
+ *
+ * In the case of a short read we start with find_task_by_pid.
+ *
+ * In the case of a seek we start with the leader and walk nr
+ * threads past it.
  */
-static int get_tgid_list(int index, unsigned long version, unsigned int *tgids)
-{
-       struct task_struct *p;
-       int nr_tgids = 0;
-
-       index--;
-       read_lock(&tasklist_lock);
-       p = NULL;
-       if (version) {
-               p = find_task_by_real_pid(version);
-               if (p && !thread_group_leader(p))
-                       p = NULL;
-       }
+static struct task_struct *first_tid(struct task_struct *leader,
+                                       int tid, int nr)
+{
+       struct task_struct *pos;
 
-       if (p)
-               index = 0;
-       else
-               p = next_task(&init_task);
+       rcu_read_lock();
+       /* Attempt to start with the pid of a thread */
+       if (tid && (nr > 0)) {
+               pos = find_task_by_pid(tid);
+               if (pos && (pos->group_leader == leader))
+                       goto found;
+       }
 
-       for ( ; p != &init_task; p = next_task(p)) {
-               int tgid = p->pid;
+       /* If nr exceeds the number of threads there is nothing todo */
+       pos = NULL;
+       if (nr && nr >= get_nr_threads(leader))
+               goto out;
 
-               if (!pid_alive(p))
-                       continue;
-               /* check for context visibility */
-               if (!proc_pid_visible(p, tgid))
-                       continue;
-               if (--index >= 0)
-                       continue;
-               tgids[nr_tgids] = vx_map_tgid(tgid);
-               nr_tgids++;
-               if (nr_tgids >= PROC_MAXPIDS)
-                       break;
+       /* If we haven't found our starting place yet start
+        * with the leader and walk nr threads forward.
+        */
+       for (pos = leader; nr > 0; --nr) {
+               pos = next_thread(pos);
+               if (pos == leader) {
+                       pos = NULL;
+                       goto out;
+               }
        }
-       read_unlock(&tasklist_lock);
-       return nr_tgids;
+found:
+       get_task_struct(pos);
+out:
+       rcu_read_unlock();
+       return pos;
 }
 
 /*
- * Get a few tid's to return for filldir - we need to hold the
- * tasklist lock while doing this, and we must release it before
- * we actually do the filldir itself, so we use a temp buffer..
+ * Find the next thread in the thread list.
+ * Return NULL if there is an error or no next thread.
+ *
+ * The reference to the input task_struct is released.
  */
-static int get_tid_list(int index, unsigned int *tids, struct inode *dir)
-{
-       struct task_struct *leader_task = proc_task(dir);
-       struct task_struct *task = leader_task;
-       int nr_tids = 0;
-
-       index -= 2;
-       read_lock(&tasklist_lock);
-       /*
-        * The starting point task (leader_task) might be an already
-        * unlinked task, which cannot be used to access the task-list
-        * via next_thread().
-        */
-       if (pid_alive(task)) do {
-               int tid = task->pid;
-
-               /* check for context visibility */
-               if (!proc_pid_visible(task, tid))
-                       continue;
-               if (--index >= 0)
-                       continue;
-               if (tids != NULL)
-                       tids[nr_tids] = vx_map_pid(tid);
-               nr_tids++;
-               if (nr_tids >= PROC_MAXPIDS)
-                       break;
-       } while ((task = next_thread(task)) != leader_task);
-       read_unlock(&tasklist_lock);
-       return nr_tids;
+static struct task_struct *next_tid(struct task_struct *start)
+{
+       struct task_struct *pos = NULL;
+       rcu_read_lock();
+       if (pid_alive(start)) {
+               pos = next_thread(start);
+               if (thread_group_leader(pos))
+                       pos = NULL;
+               else
+                       get_task_struct(pos);
+       }
+       rcu_read_unlock();
+       put_task_struct(start);
+       return pos;
 }
 
-/* for the /proc/ directory itself, after non-process stuff has been done */
-int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
+static int proc_task_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+       struct task_struct *task, int tid)
 {
-       unsigned int tgid_array[PROC_MAXPIDS];
-       char buf[PROC_NUMBUF];
-       unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY;
-       unsigned int nr_tgids, i;
-       int next_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++;
-       }
-
-       /* f_version caches the tgid value that the last readdir call couldn't
-        * return. lseek aka telldir automagically resets f_version to 0.
-        */
-       next_tgid = filp->f_version;
-       filp->f_version = 0;
-       for (;;) {
-               nr_tgids = get_tgid_list(nr, next_tgid, tgid_array);
-               if (!nr_tgids) {
-                       /* no more entries ! */
-                       break;
-               }
-               next_tgid = 0;
-
-               /* do not use the last found pid, reserve it for next_tgid */
-               if (nr_tgids == PROC_MAXPIDS) {
-                       nr_tgids--;
-                       next_tgid = tgid_array[nr_tgids];
-               }
-
-               for (i=0;i<nr_tgids;i++) {
-                       int tgid = tgid_array[i];
-                       ino_t ino = fake_ino(tgid,PROC_TGID_INO);
-                       unsigned long j = PROC_NUMBUF;
-
-                       do
-                               buf[--j] = '0' + (tgid % 10);
-                       while ((tgid /= 10) != 0);
-
-                       if (filldir(dirent, buf+j, PROC_NUMBUF-j, 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_array[i];
-                               goto out;
-                       }
-                       filp->f_pos++;
-                       nr++;
-               }
-       }
-out:
-       return 0;
+       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)
 {
-       unsigned int tid_array[PROC_MAXPIDS];
-       char buf[PROC_NUMBUF];
-       unsigned int nr_tids, i;
-       struct dentry *dentry = filp->f_dentry;
+       struct dentry *dentry = filp->f_path.dentry;
        struct inode *inode = dentry->d_inode;
-       struct task_struct *task = 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 */
 
-       if (!vx_check(vx_task_xid(task), VX_WATCH|VX_IDENT))
-               goto out;
-       if (!pid_alive(task))
-               goto out;
+       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;
 
        switch (pos) {
@@ -2370,24 +2447,53 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi
                /* fall through */
        }
 
-       nr_tids = get_tid_list(pos, tid_array, inode);
-       inode->i_nlink = pos + nr_tids;
-
-       for (i = 0; i < nr_tids; i++) {
-               unsigned long j = PROC_NUMBUF;
-               int tid = tid_array[i];
-
-               ino = fake_ino(tid,PROC_TID_INO);
-
-               do
-                       buf[--j] = '0' + (tid % 10);
-               while ((tid /= 10) != 0);
-
-               if (filldir(dirent, buf+j, PROC_NUMBUF-j, pos, ino, DT_DIR) < 0)
+       /* f_version caches the tgid value that the last readdir call couldn't
+        * return. lseek aka telldir automagically resets f_version to 0.
+        */
+       tid = filp->f_version;
+       filp->f_version = 0;
+       for (task = first_tid(leader, tid, pos - 2);
+            task;
+            task = next_tid(task), pos++) {
+               tid = vx_map_pid(task->pid);
+               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;
+                       put_task_struct(task);
                        break;
-               pos++;
+               }
        }
 out:
        filp->f_pos = pos;
+       put_task_struct(leader);
+out_no_task:
        return retval;
 }
+
+static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+{
+       struct inode *inode = dentry->d_inode;
+       struct task_struct *p = get_proc_task(inode);
+       generic_fillattr(inode, stat);
+
+       if (p) {
+               rcu_read_lock();
+               stat->nlink += get_nr_threads(p);
+               rcu_read_unlock();
+               put_task_struct(p);
+       }
+
+       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,
+};