[PATCH] elf: fix kcore note size calculation
[powerpc.git] / fs / proc / base.c
index cb0cf84..05ace70 100644 (file)
@@ -71,6 +71,8 @@
 #include <linux/cpuset.h>
 #include <linux/audit.h>
 #include <linux/poll.h>
+#include <linux/nsproxy.h>
+#include <linux/oom.h>
 #include "internal.h"
 
 /* NOTE:
  *     in /proc for a task before it execs a suid executable.
  */
 
-/*
- * For hysterical raisins we keep the same inumbers as in the old procfs.
- * Feel free to change the macro below - just keep the range distinct from
- * inumbers of the rest of procfs (currently those are in 0x0000--0xffff).
- * As soon as we'll get a separate superblock we will be able to forget
- * about magical ranges too.
- */
-
-#define fake_ino(pid,ino) (((pid)<<16)|(ino))
-
-enum pid_directory_inos {
-       PROC_TGID_INO = 2,
-       PROC_TGID_TASK,
-       PROC_TGID_STATUS,
-       PROC_TGID_MEM,
-#ifdef CONFIG_SECCOMP
-       PROC_TGID_SECCOMP,
-#endif
-       PROC_TGID_CWD,
-       PROC_TGID_ROOT,
-       PROC_TGID_EXE,
-       PROC_TGID_FD,
-       PROC_TGID_ENVIRON,
-       PROC_TGID_AUXV,
-       PROC_TGID_CMDLINE,
-       PROC_TGID_STAT,
-       PROC_TGID_STATM,
-       PROC_TGID_MAPS,
-       PROC_TGID_NUMA_MAPS,
-       PROC_TGID_MOUNTS,
-       PROC_TGID_MOUNTSTATS,
-       PROC_TGID_WCHAN,
-#ifdef CONFIG_MMU
-       PROC_TGID_SMAPS,
-#endif
-#ifdef CONFIG_SCHEDSTATS
-       PROC_TGID_SCHEDSTAT,
-#endif
-#ifdef CONFIG_CPUSETS
-       PROC_TGID_CPUSET,
-#endif
-#ifdef CONFIG_SECURITY
-       PROC_TGID_ATTR,
-       PROC_TGID_ATTR_CURRENT,
-       PROC_TGID_ATTR_PREV,
-       PROC_TGID_ATTR_EXEC,
-       PROC_TGID_ATTR_FSCREATE,
-       PROC_TGID_ATTR_KEYCREATE,
-       PROC_TGID_ATTR_SOCKCREATE,
-#endif
-#ifdef CONFIG_AUDITSYSCALL
-       PROC_TGID_LOGINUID,
-#endif
-       PROC_TGID_OOM_SCORE,
-       PROC_TGID_OOM_ADJUST,
-       PROC_TID_INO,
-       PROC_TID_STATUS,
-       PROC_TID_MEM,
-#ifdef CONFIG_SECCOMP
-       PROC_TID_SECCOMP,
-#endif
-       PROC_TID_CWD,
-       PROC_TID_ROOT,
-       PROC_TID_EXE,
-       PROC_TID_FD,
-       PROC_TID_ENVIRON,
-       PROC_TID_AUXV,
-       PROC_TID_CMDLINE,
-       PROC_TID_STAT,
-       PROC_TID_STATM,
-       PROC_TID_MAPS,
-       PROC_TID_NUMA_MAPS,
-       PROC_TID_MOUNTS,
-       PROC_TID_MOUNTSTATS,
-       PROC_TID_WCHAN,
-#ifdef CONFIG_MMU
-       PROC_TID_SMAPS,
-#endif
-#ifdef CONFIG_SCHEDSTATS
-       PROC_TID_SCHEDSTAT,
-#endif
-#ifdef CONFIG_CPUSETS
-       PROC_TID_CPUSET,
-#endif
-#ifdef CONFIG_SECURITY
-       PROC_TID_ATTR,
-       PROC_TID_ATTR_CURRENT,
-       PROC_TID_ATTR_PREV,
-       PROC_TID_ATTR_EXEC,
-       PROC_TID_ATTR_FSCREATE,
-       PROC_TID_ATTR_KEYCREATE,
-       PROC_TID_ATTR_SOCKCREATE,
-#endif
-#ifdef CONFIG_AUDITSYSCALL
-       PROC_TID_LOGINUID,
-#endif
-       PROC_TID_OOM_SCORE,
-       PROC_TID_OOM_ADJUST,
-
-       /* Add new entries before this */
-       PROC_TID_FD_DIR = 0x8000,       /* 0x8000-0xffff */
-};
 
 /* Worst case buffer size needed for holding an integer. */
-#define PROC_NUMBUF 10
+#define PROC_NUMBUF 13
 
 struct pid_entry {
-       int type;
        int len;
        char *name;
        mode_t mode;
+       struct inode_operations *iop;
+       struct file_operations *fop;
+       union proc_op op;
 };
 
-#define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)}
+#define NOD(NAME, MODE, IOP, FOP, OP) {                        \
+       .len  = sizeof(NAME) - 1,                       \
+       .name = (NAME),                                 \
+       .mode = MODE,                                   \
+       .iop  = IOP,                                    \
+       .fop  = FOP,                                    \
+       .op   = OP,                                     \
+}
+
+#define DIR(NAME, MODE, OTYPE)                                                 \
+       NOD(NAME, (S_IFDIR|(MODE)),                                             \
+               &proc_##OTYPE##_inode_operations, &proc_##OTYPE##_operations,   \
+               {} )
+#define LNK(NAME, OTYPE)                                       \
+       NOD(NAME, (S_IFLNK|S_IRWXUGO),                          \
+               &proc_pid_link_inode_operations, NULL,          \
+               { .proc_get_link = &proc_##OTYPE##_link } )
+#define REG(NAME, MODE, OTYPE)                         \
+       NOD(NAME, (S_IFREG|(MODE)), NULL,               \
+               &proc_##OTYPE##_operations, {})
+#define INF(NAME, MODE, OTYPE)                         \
+       NOD(NAME, (S_IFREG|(MODE)),                     \
+               NULL, &proc_info_file_operations,       \
+               { .proc_read = &proc_##OTYPE } )
 
 static struct fs_struct *get_fs_struct(struct task_struct *task)
 {
@@ -446,7 +371,7 @@ static int mounts_open(struct inode *inode, struct file *file)
 
        if (task) {
                task_lock(task);
-               namespace = task->namespace;
+               namespace = task->nsproxy->namespace;
                if (namespace)
                        get_namespace(namespace);
                task_unlock(task);
@@ -517,7 +442,8 @@ static int mountstats_open(struct inode *inode, struct file *file)
 
                if (task) {
                        task_lock(task);
-                       namespace = task->namespace;
+                       if (task->nsproxy)
+                               namespace = task->nsproxy->namespace;
                        if (namespace)
                                get_namespace(namespace);
                        task_unlock(task);
@@ -757,21 +683,24 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
        char buffer[PROC_NUMBUF], *end;
        int oom_adjust;
 
-       if (!capable(CAP_SYS_RESOURCE))
-               return -EPERM;
        memset(buffer, 0, sizeof(buffer));
        if (count > sizeof(buffer) - 1)
                count = sizeof(buffer) - 1;
        if (copy_from_user(buffer, buf, count))
                return -EFAULT;
        oom_adjust = simple_strtol(buffer, &end, 0);
-       if ((oom_adjust < -16 || oom_adjust > 15) && oom_adjust != OOM_DISABLE)
+       if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) &&
+            oom_adjust != OOM_DISABLE)
                return -EINVAL;
        if (*end == '\n')
                end++;
        task = get_proc_task(file->f_dentry->d_inode);
        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)
@@ -1015,7 +944,7 @@ 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;
@@ -1029,13 +958,12 @@ static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_st
        /* Common stuff */
        ei = PROC_I(inode);
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-       inode->i_ino = fake_ino(task->pid, ino);
        inode->i_op = &proc_def_inode_operations;
 
        /*
         * grab the reference to task.
         */
-       ei->pid = get_pid(task->pids[PIDTYPE_PID].pid);
+       ei->pid = get_task_pid(task, PIDTYPE_PID);
        if (!ei->pid)
                goto out_unlock;
 
@@ -1132,6 +1060,62 @@ static struct dentry_operations pid_dentry_operations =
 
 /* Lookups */
 
+typedef struct dentry *instantiate_t(struct inode *, struct dentry *, struct task_struct *, void *);
+
+/*
+ * Fill a directory entry.
+ *
+ * If possible create the dcache entry and derive our inode number and
+ * file type from dcache entry.
+ *
+ * Since all of the proc inode numbers are dynamically generated, the inode
+ * numbers do not exist until the inode is cache.  This means creating the
+ * the dcache entry in readdir is necessary to keep the inode numbers
+ * reported by readdir in sync with the inode numbers reported
+ * by stat.
+ */
+static int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+       char *name, int len,
+       instantiate_t instantiate, struct task_struct *task, void *ptr)
+{
+       struct dentry *child, *dir = filp->f_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;
@@ -1226,30 +1210,24 @@ static struct dentry_operations tid_fd_dentry_operations =
        .d_delete       = pid_delete_dentry,
 };
 
-/* SMP-safe */
-static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+static struct dentry *proc_fd_instantiate(struct inode *dir,
+       struct dentry *dentry, struct task_struct *task, void *ptr)
 {
-       struct task_struct *task = get_proc_task(dir);
-       unsigned fd = name_to_int(dentry);
-       struct dentry *result = ERR_PTR(-ENOENT);
-       struct file * file;
-       struct files_struct * files;
-       struct inode *inode;
-       struct proc_inode *ei;
-
-       if (!task)
-               goto out_no_task;
-       if (fd == ~0U)
-               goto out;
+       unsigned fd = *(unsigned *)ptr;
+       struct file *file;
+       struct files_struct *files;
+       struct inode *inode;
+       struct proc_inode *ei;
+       struct dentry *error = ERR_PTR(-ENOENT);
 
-       inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_FD_DIR+fd);
+       inode = proc_pid_make_inode(dir->i_sb, task);
        if (!inode)
                goto out;
        ei = PROC_I(inode);
        ei->fd = fd;
        files = get_files_struct(task);
        if (!files)
-               goto out_unlock;
+               goto out_iput;
        inode->i_mode = S_IFLNK;
 
        /*
@@ -1259,13 +1237,14 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
        spin_lock(&files->file_lock);
        file = fcheck_files(files, fd);
        if (!file)
-               goto out_unlock2;
+               goto out_unlock;
        if (file->f_mode & 1)
                inode->i_mode |= S_IRUSR | S_IXUSR;
        if (file->f_mode & 2)
                inode->i_mode |= S_IWUSR | S_IXUSR;
        spin_unlock(&files->file_lock);
        put_files_struct(files);
+
        inode->i_op = &proc_pid_link_inode_operations;
        inode->i_size = 64;
        ei->op.proc_get_link = proc_fd_link;
@@ -1273,20 +1252,45 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
        if (tid_fd_revalidate(dentry, NULL))
-               result = NULL;
-out:
-       put_task_struct(task);
-out_no_task:
-       return result;
+               error = NULL;
 
-out_unlock2:
+ out:
+       return error;
+out_unlock:
        spin_unlock(&files->file_lock);
        put_files_struct(files);
-out_unlock:
+out_iput:
        iput(inode);
        goto out;
 }
 
+static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+{
+       struct task_struct *task = get_proc_task(dir);
+       unsigned fd = name_to_int(dentry);
+       struct dentry *result = ERR_PTR(-ENOENT);
+
+       if (!task)
+               goto out_no_task;
+       if (fd == ~0U)
+               goto out;
+
+       result = proc_fd_instantiate(dir, dentry, task, &fd);
+out:
+       put_task_struct(task);
+out_no_task:
+       return result;
+}
+
+static int proc_fd_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+       struct task_struct *task, int fd)
+{
+       char name[PROC_NUMBUF];
+       int len = snprintf(name, sizeof(name), "%d", fd);
+       return proc_fill_cache(filp, dirent, filldir, name, len,
+                               proc_fd_instantiate, task, &fd);
+}
+
 static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
 {
        struct dentry *dentry = filp->f_dentry;
@@ -1294,7 +1298,6 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
        struct task_struct *p = get_proc_task(inode);
        unsigned int fd, tid, ino;
        int retval;
-       char buf[PROC_NUMBUF];
        struct files_struct * files;
        struct fdtable *fdt;
 
@@ -1324,22 +1327,12 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
                        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 = PROC_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, PROC_NUMBUF-j, fd+2, ino, DT_LNK) < 0) {
+                               if (proc_fd_fill_cache(filp, dirent, filldir, p, fd) < 0) {
                                        rcu_read_lock();
                                        break;
                                }
@@ -1367,27 +1360,45 @@ static struct inode_operations proc_fd_inode_operations = {
        .setattr        = proc_setattr,
 };
 
-static struct file_operations proc_task_operations;
-static struct inode_operations proc_task_inode_operations;
+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);
 
-#ifdef CONFIG_SECURITY
-static struct file_operations proc_pid_attr_operations;
-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;
-#endif
+       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;
+}
 
-/* SMP-safe */
 static struct dentry *proc_pident_lookup(struct inode *dir, 
                                         struct dentry *dentry,
-                                        struct pid_entry *ents)
+                                        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;
-       struct proc_inode *ei;
+       struct pid_entry *p, *last;
 
        error = ERR_PTR(-ENOENT);
        inode = NULL;
@@ -1395,198 +1406,34 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
        if (!task)
                goto out_no_task;
 
-       for (p = ents; p->name; p++) {
+       /*
+        * 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->name)
+       if (p > last)
                goto out;
 
-       error = ERR_PTR(-EINVAL);
-       inode = proc_pid_make_inode(dir->i_sb, task, p->type);
-       if (!inode)
-               goto out;
-
-       ei = PROC_I(inode);
-       inode->i_mode = p->mode;
-       /*
-        * Yes, it does not scale. And it should not. Don't add
-        * new entries into /proc/<tgid>/ without very good reasons.
-        */
-       switch(p->type) {
-               case PROC_TGID_TASK:
-                       inode->i_nlink = 2;
-                       inode->i_op = &proc_task_inode_operations;
-                       inode->i_fop = &proc_task_operations;
-                       break;
-               case PROC_TID_FD:
-               case PROC_TGID_FD:
-                       inode->i_nlink = 2;
-                       inode->i_op = &proc_fd_inode_operations;
-                       inode->i_fop = &proc_fd_operations;
-                       break;
-               case PROC_TID_EXE:
-               case PROC_TGID_EXE:
-                       inode->i_op = &proc_pid_link_inode_operations;
-                       ei->op.proc_get_link = proc_exe_link;
-                       break;
-               case PROC_TID_CWD:
-               case PROC_TGID_CWD:
-                       inode->i_op = &proc_pid_link_inode_operations;
-                       ei->op.proc_get_link = proc_cwd_link;
-                       break;
-               case PROC_TID_ROOT:
-               case PROC_TGID_ROOT:
-                       inode->i_op = &proc_pid_link_inode_operations;
-                       ei->op.proc_get_link = proc_root_link;
-                       break;
-               case PROC_TID_ENVIRON:
-               case PROC_TGID_ENVIRON:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_pid_environ;
-                       break;
-               case PROC_TID_AUXV:
-               case PROC_TGID_AUXV:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_pid_auxv;
-                       break;
-               case PROC_TID_STATUS:
-               case PROC_TGID_STATUS:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_pid_status;
-                       break;
-               case PROC_TID_STAT:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_tid_stat;
-                       break;
-               case PROC_TGID_STAT:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_tgid_stat;
-                       break;
-               case PROC_TID_CMDLINE:
-               case PROC_TGID_CMDLINE:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_pid_cmdline;
-                       break;
-               case PROC_TID_STATM:
-               case PROC_TGID_STATM:
-                       inode->i_fop = &proc_info_file_operations;
-                       ei->op.proc_read = proc_pid_statm;
-                       break;
-               case PROC_TID_MAPS:
-               case PROC_TGID_MAPS:
-                       inode->i_fop = &proc_maps_operations;
-                       break;
-#ifdef CONFIG_NUMA
-               case PROC_TID_NUMA_MAPS:
-               case PROC_TGID_NUMA_MAPS:
-                       inode->i_fop = &proc_numa_maps_operations;
-                       break;
-#endif
-               case PROC_TID_MEM:
-               case PROC_TGID_MEM:
-                       inode->i_fop = &proc_mem_operations;
-                       break;
-#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;
-#ifdef CONFIG_MMU
-               case PROC_TID_SMAPS:
-               case PROC_TGID_SMAPS:
-                       inode->i_fop = &proc_smaps_operations;
-                       break;
-#endif
-               case PROC_TID_MOUNTSTATS:
-               case PROC_TGID_MOUNTSTATS:
-                       inode->i_fop = &proc_mountstats_operations;
-                       break;
-#ifdef CONFIG_SECURITY
-               case PROC_TID_ATTR:
-                       inode->i_nlink = 2;
-                       inode->i_op = &proc_tid_attr_inode_operations;
-                       inode->i_fop = &proc_tid_attr_operations;
-                       break;
-               case PROC_TGID_ATTR:
-                       inode->i_nlink = 2;
-                       inode->i_op = &proc_tgid_attr_inode_operations;
-                       inode->i_fop = &proc_tgid_attr_operations;
-                       break;
-               case PROC_TID_ATTR_CURRENT:
-               case PROC_TGID_ATTR_CURRENT:
-               case PROC_TID_ATTR_PREV:
-               case PROC_TGID_ATTR_PREV:
-               case PROC_TID_ATTR_EXEC:
-               case PROC_TGID_ATTR_EXEC:
-               case PROC_TID_ATTR_FSCREATE:
-               case PROC_TGID_ATTR_FSCREATE:
-               case PROC_TID_ATTR_KEYCREATE:
-               case PROC_TGID_ATTR_KEYCREATE:
-               case PROC_TID_ATTR_SOCKCREATE:
-               case PROC_TGID_ATTR_SOCKCREATE:
-                       inode->i_fop = &proc_pid_attr_operations;
-                       break;
-#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;
-#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;
-#endif
-#ifdef CONFIG_CPUSETS
-               case PROC_TID_CPUSET:
-               case PROC_TGID_CPUSET:
-                       inode->i_fop = &proc_cpuset_operations;
-                       break;
-#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;
-#ifdef CONFIG_AUDITSYSCALL
-               case PROC_TID_LOGINUID:
-               case PROC_TGID_LOGINUID:
-                       inode->i_fop = &proc_loginuid_operations;
-                       break;
-#endif
-               default:
-                       printk("procfs: impossible type (%d)",p->type);
-                       iput(inode);
-                       error = ERR_PTR(-EINVAL);
-                       goto out;
-       }
-       dentry->d_op = &pid_dentry_operations;
-       d_add(dentry, inode);
-       /* Close the race of the process dying before we return the dentry */
-       if (pid_revalidate(dentry, NULL))
-               error = NULL;
+       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)
@@ -1596,17 +1443,16 @@ static int proc_pident_readdir(struct file *filp,
        struct dentry *dentry = filp->f_dentry;
        struct inode *inode = dentry->d_inode;
        struct task_struct *task = get_proc_task(inode);
-       struct pid_entry *p;
+       struct pid_entry *p, *last;
        ino_t ino;
        int ret;
 
        ret = -ENOENT;
        if (!task)
-               goto out;
+               goto out_no_task;
 
        ret = 0;
        pid = task->pid;
-       put_task_struct(task);
        i = filp->f_pos;
        switch (i) {
        case 0:
@@ -1630,9 +1476,9 @@ static int proc_pident_readdir(struct file *filp,
                        goto out;
                }
                p = ents + i;
-               while (p->name) {
-                       if (filldir(dirent, p->name, p->len, filp->f_pos,
-                                   fake_ino(pid, p->type), p->mode >> 12) < 0)
+               last = &ents[nents - 1];
+               while (p <= last) {
+                       if (proc_pident_fill_cache(filp, dirent, filldir, task, p) < 0)
                                goto out;
                        filp->f_pos++;
                        p++;
@@ -1641,6 +1487,8 @@ static int proc_pident_readdir(struct file *filp,
 
        ret = 1;
 out:
+       put_task_struct(task);
+out_no_task:
        return ret;
 }
 
@@ -1719,72 +1567,40 @@ static struct file_operations proc_pid_attr_operations = {
        .write          = proc_pid_attr_write,
 };
 
-static struct pid_entry tgid_attr_stuff[] = {
-       E(PROC_TGID_ATTR_CURRENT,  "current",  S_IFREG|S_IRUGO|S_IWUGO),
-       E(PROC_TGID_ATTR_PREV,     "prev",     S_IFREG|S_IRUGO),
-       E(PROC_TGID_ATTR_EXEC,     "exec",     S_IFREG|S_IRUGO|S_IWUGO),
-       E(PROC_TGID_ATTR_FSCREATE, "fscreate", S_IFREG|S_IRUGO|S_IWUGO),
-       E(PROC_TGID_ATTR_KEYCREATE, "keycreate", S_IFREG|S_IRUGO|S_IWUGO),
-       E(PROC_TGID_ATTR_SOCKCREATE, "sockcreate", S_IFREG|S_IRUGO|S_IWUGO),
-       {0,0,NULL,0}
-};
-static struct pid_entry tid_attr_stuff[] = {
-       E(PROC_TID_ATTR_CURRENT,   "current",  S_IFREG|S_IRUGO|S_IWUGO),
-       E(PROC_TID_ATTR_PREV,      "prev",     S_IFREG|S_IRUGO),
-       E(PROC_TID_ATTR_EXEC,      "exec",     S_IFREG|S_IRUGO|S_IWUGO),
-       E(PROC_TID_ATTR_FSCREATE,  "fscreate", S_IFREG|S_IRUGO|S_IWUGO),
-       E(PROC_TID_ATTR_KEYCREATE, "keycreate", S_IFREG|S_IRUGO|S_IWUGO),
-       E(PROC_TID_ATTR_SOCKCREATE, "sockcreate", S_IFREG|S_IRUGO|S_IWUGO),
-       {0,0,NULL,0}
+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_tgid_attr_readdir(struct file * filp,
-                            void * dirent, filldir_t filldir)
-{
-       return proc_pident_readdir(filp,dirent,filldir,
-                                  tgid_attr_stuff,ARRAY_SIZE(tgid_attr_stuff));
-}
-
-static int proc_tid_attr_readdir(struct file * filp,
+static int proc_attr_dir_readdir(struct file * filp,
                             void * dirent, filldir_t filldir)
 {
        return proc_pident_readdir(filp,dirent,filldir,
-                                  tid_attr_stuff,ARRAY_SIZE(tid_attr_stuff));
+                                  attr_dir_stuff,ARRAY_SIZE(attr_dir_stuff));
 }
 
-static struct file_operations proc_tgid_attr_operations = {
+static struct file_operations proc_attr_dir_operations = {
        .read           = generic_read_dir,
-       .readdir        = proc_tgid_attr_readdir,
+       .readdir        = proc_attr_dir_readdir,
 };
 
-static struct file_operations proc_tid_attr_operations = {
-       .read           = generic_read_dir,
-       .readdir        = proc_tid_attr_readdir,
-};
-
-static struct dentry *proc_tgid_attr_lookup(struct inode *dir,
+static struct dentry *proc_attr_dir_lookup(struct inode *dir,
                                struct dentry *dentry, struct nameidata *nd)
 {
-       return proc_pident_lookup(dir, dentry, tgid_attr_stuff);
+       return proc_pident_lookup(dir, dentry,
+                                 attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff));
 }
 
-static struct dentry *proc_tid_attr_lookup(struct inode *dir,
-                               struct dentry *dentry, struct nameidata *nd)
-{
-       return proc_pident_lookup(dir, dentry, tid_attr_stuff);
-}
-
-static struct inode_operations proc_tgid_attr_inode_operations = {
-       .lookup         = proc_tgid_attr_lookup,
+static struct inode_operations proc_attr_dir_inode_operations = {
+       .lookup         = proc_attr_dir_lookup,
        .getattr        = pid_getattr,
        .setattr        = proc_setattr,
 };
 
-static struct inode_operations proc_tid_attr_inode_operations = {
-       .lookup         = proc_tid_attr_lookup,
-       .getattr        = pid_getattr,
-       .setattr        = proc_setattr,
-};
 #endif
 
 /*
@@ -1810,52 +1626,173 @@ static struct inode_operations proc_self_inode_operations = {
        .follow_link    = proc_self_follow_link,
 };
 
+/*
+ * proc base
+ *
+ * These are the directory entries in the root directory of /proc
+ * that properly belong to the /proc filesystem, as they describe
+ * describe something that is process related.
+ */
+static struct pid_entry proc_base_stuff[] = {
+       NOD("self", S_IFLNK|S_IRWXUGO,
+               &proc_self_inode_operations, NULL, {}),
+};
+
+/*
+ *     Exceptional case: normally we are not allowed to unhash a busy
+ * directory. In this case, however, we can do it - no aliasing problems
+ * due to the way we treat inodes.
+ */
+static int proc_base_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+       struct inode *inode = dentry->d_inode;
+       struct task_struct *task = get_proc_task(inode);
+       if (task) {
+               put_task_struct(task);
+               return 1;
+       }
+       d_drop(dentry);
+       return 0;
+}
+
+static struct dentry_operations proc_base_dentry_operations =
+{
+       .d_revalidate   = proc_base_revalidate,
+       .d_delete       = pid_delete_dentry,
+};
+
+static struct dentry *proc_base_instantiate(struct inode *dir,
+       struct dentry *dentry, struct task_struct *task, void *ptr)
+{
+       struct pid_entry *p = ptr;
+       struct inode *inode;
+       struct proc_inode *ei;
+       struct dentry *error = ERR_PTR(-EINVAL);
+
+       /* Allocate the inode */
+       error = ERR_PTR(-ENOMEM);
+       inode = new_inode(dir->i_sb);
+       if (!inode)
+               goto out;
+
+       /* Initialize the inode */
+       ei = PROC_I(inode);
+       inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+
+       /*
+        * grab the reference to the task.
+        */
+       ei->pid = get_task_pid(task, PIDTYPE_PID);
+       if (!ei->pid)
+               goto out_iput;
+
+       inode->i_uid = 0;
+       inode->i_gid = 0;
+       inode->i_mode = p->mode;
+       if (S_ISDIR(inode->i_mode))
+               inode->i_nlink = 2;
+       if (S_ISLNK(inode->i_mode))
+               inode->i_size = 64;
+       if (p->iop)
+               inode->i_op = p->iop;
+       if (p->fop)
+               inode->i_fop = p->fop;
+       ei->op = p->op;
+       dentry->d_op = &proc_base_dentry_operations;
+       d_add(dentry, inode);
+       error = NULL;
+out:
+       return error;
+out_iput:
+       iput(inode);
+       goto out;
+}
+
+static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
+{
+       struct dentry *error;
+       struct task_struct *task = get_proc_task(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 > last)
+               goto out;
+
+       error = proc_base_instantiate(dir, dentry, task, p);
+
+out:
+       put_task_struct(task);
+out_no_task:
+       return error;
+}
+
+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);
+}
+
 /*
  * Thread groups
  */
+static struct file_operations proc_task_operations;
+static struct inode_operations proc_task_inode_operations;
+
 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),
+       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_IRUGO, maps),
 #ifdef CONFIG_NUMA
-       E(PROC_TGID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO),
+       REG("numa_maps",  S_IRUGO, numa_maps),
 #endif
-       E(PROC_TGID_MEM,       "mem",     S_IFREG|S_IRUSR|S_IWUSR),
+       REG("mem",        S_IRUSR|S_IWUSR, mem),
 #ifdef CONFIG_SECCOMP
-       E(PROC_TGID_SECCOMP,   "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
+       REG("seccomp",    S_IRUSR|S_IWUSR, seccomp),
 #endif
-       E(PROC_TGID_CWD,       "cwd",     S_IFLNK|S_IRWXUGO),
-       E(PROC_TGID_ROOT,      "root",    S_IFLNK|S_IRWXUGO),
-       E(PROC_TGID_EXE,       "exe",     S_IFLNK|S_IRWXUGO),
-       E(PROC_TGID_MOUNTS,    "mounts",  S_IFREG|S_IRUGO),
-       E(PROC_TGID_MOUNTSTATS, "mountstats", S_IFREG|S_IRUSR),
+       LNK("cwd",        cwd),
+       LNK("root",       root),
+       LNK("exe",        exe),
+       REG("mounts",     S_IRUGO, mounts),
+       REG("mountstats", S_IRUSR, mountstats),
 #ifdef CONFIG_MMU
-       E(PROC_TGID_SMAPS,     "smaps",   S_IFREG|S_IRUGO),
+       REG("smaps",      S_IRUGO, smaps),
 #endif
 #ifdef CONFIG_SECURITY
-       E(PROC_TGID_ATTR,      "attr",    S_IFDIR|S_IRUGO|S_IXUGO),
+       DIR("attr",       S_IRUGO|S_IXUGO, attr_dir),
 #endif
 #ifdef CONFIG_KALLSYMS
-       E(PROC_TGID_WCHAN,     "wchan",   S_IFREG|S_IRUGO),
+       INF("wchan",      S_IRUGO, pid_wchan),
 #endif
 #ifdef CONFIG_SCHEDSTATS
-       E(PROC_TGID_SCHEDSTAT, "schedstat", S_IFREG|S_IRUGO),
+       INF("schedstat",  S_IRUGO, pid_schedstat),
 #endif
 #ifdef CONFIG_CPUSETS
-       E(PROC_TGID_CPUSET,    "cpuset",  S_IFREG|S_IRUGO),
+       REG("cpuset",     S_IRUGO, cpuset),
 #endif
-       E(PROC_TGID_OOM_SCORE, "oom_score",S_IFREG|S_IRUGO),
-       E(PROC_TGID_OOM_ADJUST,"oom_adj", S_IFREG|S_IRUGO|S_IWUSR),
+       INF("oom_score",  S_IRUGO, oom_score),
+       REG("oom_adj",    S_IRUGO|S_IWUSR, oom_adjust),
 #ifdef CONFIG_AUDITSYSCALL
-       E(PROC_TGID_LOGINUID, "loginuid", S_IFREG|S_IWUSR|S_IRUGO),
+       REG("loginuid",   S_IWUSR|S_IRUGO, loginuid),
 #endif
-       {0,0,NULL,0}
 };
 
 static int proc_tgid_base_readdir(struct file * filp,
@@ -1871,7 +1808,8 @@ static struct file_operations proc_tgid_base_operations = {
 };
 
 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);
+       return proc_pident_lookup(dir, dentry,
+                                 tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff));
 }
 
 static struct inode_operations proc_tgid_base_inode_operations = {
@@ -1947,54 +1885,23 @@ out:
        return;
 }
 
-/* SMP-safe */
-struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
+struct dentry *proc_pid_instantiate(struct inode *dir,
+       struct dentry * dentry, struct task_struct *task, void *ptr)
 {
-       struct dentry *result = ERR_PTR(-ENOENT);
-       struct task_struct *task;
+       struct dentry *error = ERR_PTR(-ENOENT);
        struct inode *inode;
-       struct proc_inode *ei;
-       unsigned tgid;
-
-       if (dentry->d_name.len == 4 && !memcmp(dentry->d_name.name,"self",4)) {
-               inode = new_inode(dir->i_sb);
-               if (!inode)
-                       return ERR_PTR(-ENOMEM);
-               ei = PROC_I(inode);
-               inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-               inode->i_ino = fake_ino(0, PROC_TGID_INO);
-               ei->pde = NULL;
-               inode->i_mode = S_IFLNK|S_IRWXUGO;
-               inode->i_uid = inode->i_gid = 0;
-               inode->i_size = 64;
-               inode->i_op = &proc_self_inode_operations;
-               d_add(dentry, inode);
-               return NULL;
-       }
-       tgid = name_to_int(dentry);
-       if (tgid == ~0U)
-               goto out;
-
-       rcu_read_lock();
-       task = find_task_by_pid(tgid);
-       if (task)
-               get_task_struct(task);
-       rcu_read_unlock();
-       if (!task)
-               goto out;
 
-       inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO);
+       inode = proc_pid_make_inode(dir->i_sb, task);
        if (!inode)
-               goto out_put_task;
+               goto out;
 
        inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
        inode->i_op = &proc_tgid_base_inode_operations;
        inode->i_fop = &proc_tgid_base_operations;
        inode->i_flags|=S_IMMUTABLE;
-#ifdef CONFIG_SECURITY
-       inode->i_nlink = 5;
-#else
        inode->i_nlink = 4;
+#ifdef CONFIG_SECURITY
+       inode->i_nlink += 1;
 #endif
 
        dentry->d_op = &pid_dentry_operations;
@@ -2002,9 +1909,34 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct
        d_add(dentry, inode);
        /* Close the race of the process dying before we return the dentry */
        if (pid_revalidate(dentry, NULL))
-               result = NULL;
+               error = NULL;
+out:
+       return error;
+}
 
-out_put_task:
+struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
+{
+       struct dentry *result = ERR_PTR(-ENOENT);
+       struct task_struct *task;
+       unsigned tgid;
+
+       result = proc_base_lookup(dir, dentry);
+       if (!IS_ERR(result) || PTR_ERR(result) != -ENOENT)
+               goto out;
+
+       tgid = name_to_int(dentry);
+       if (tgid == ~0U)
+               goto out;
+
+       rcu_read_lock();
+       task = find_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;
@@ -2046,41 +1978,49 @@ retry:
        return task;
 }
 
-#define TGID_OFFSET (FIRST_PROCESS_ENTRY + (1 /* /proc/self */))
+#define TGID_OFFSET (FIRST_PROCESS_ENTRY + ARRAY_SIZE(proc_base_stuff))
+
+static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+       struct task_struct *task, int tgid)
+{
+       char name[PROC_NUMBUF];
+       int len = snprintf(name, sizeof(name), "%d", tgid);
+       return proc_fill_cache(filp, dirent, filldir, name, len,
+                               proc_pid_instantiate, task, NULL);
+}
 
 /* for the /proc/ directory itself, after non-process stuff has been done */
 int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
-       char buf[PROC_NUMBUF];
        unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY;
+       struct task_struct *reaper = get_proc_task(filp->f_dentry->d_inode);
        struct task_struct *task;
        int tgid;
 
-       if (!nr) {
-               ino_t ino = fake_ino(0,PROC_TGID_INO);
-               if (filldir(dirent, "self", 4, filp->f_pos, ino, DT_LNK) < 0)
-                       return 0;
-               filp->f_pos++;
-               nr++;
+       if (!reaper)
+               goto out_no_task;
+
+       for (; nr < ARRAY_SIZE(proc_base_stuff); filp->f_pos++, nr++) {
+               struct pid_entry *p = &proc_base_stuff[nr];
+               if (proc_base_fill_cache(filp, dirent, filldir, reaper, p) < 0)
+                       goto out;
        }
 
        tgid = filp->f_pos - TGID_OFFSET;
        for (task = next_tgid(tgid);
             task;
             put_task_struct(task), task = next_tgid(tgid + 1)) {
-               int len;
-               ino_t ino;
                tgid = task->pid;
                filp->f_pos = tgid + TGID_OFFSET;
-               len = snprintf(buf, sizeof(buf), "%d", tgid);
-               ino = fake_ino(tgid, PROC_TGID_INO);
-               if (filldir(dirent, buf, len, filp->f_pos, ino, DT_DIR) < 0) {
+               if (proc_pid_fill_cache(filp, dirent, filldir, task, tgid) < 0) {
                        put_task_struct(task);
                        goto out;
                }
        }
        filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET;
 out:
+       put_task_struct(reaper);
+out_no_task:
        return 0;
 }
 
@@ -2088,46 +2028,45 @@ out:
  * Tasks
  */
 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),
+       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_IRUGO, maps),
 #ifdef CONFIG_NUMA
-       E(PROC_TID_NUMA_MAPS,  "numa_maps",    S_IFREG|S_IRUGO),
+       REG("numa_maps", S_IRUGO, numa_maps),
 #endif
-       E(PROC_TID_MEM,        "mem",     S_IFREG|S_IRUSR|S_IWUSR),
+       REG("mem",       S_IRUSR|S_IWUSR, mem),
 #ifdef CONFIG_SECCOMP
-       E(PROC_TID_SECCOMP,    "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
+       REG("seccomp",   S_IRUSR|S_IWUSR, seccomp),
 #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),
+       LNK("cwd",       cwd),
+       LNK("root",      root),
+       LNK("exe",       exe),
+       REG("mounts",    S_IRUGO, mounts),
 #ifdef CONFIG_MMU
-       E(PROC_TID_SMAPS,      "smaps",   S_IFREG|S_IRUGO),
+       REG("smaps",     S_IRUGO, smaps),
 #endif
 #ifdef CONFIG_SECURITY
-       E(PROC_TID_ATTR,       "attr",    S_IFDIR|S_IRUGO|S_IXUGO),
+       DIR("attr",      S_IRUGO|S_IXUGO, attr_dir),
 #endif
 #ifdef CONFIG_KALLSYMS
-       E(PROC_TID_WCHAN,      "wchan",   S_IFREG|S_IRUGO),
+       INF("wchan",     S_IRUGO, pid_wchan),
 #endif
 #ifdef CONFIG_SCHEDSTATS
-       E(PROC_TID_SCHEDSTAT, "schedstat",S_IFREG|S_IRUGO),
+       INF("schedstat", S_IRUGO, pid_schedstat),
 #endif
 #ifdef CONFIG_CPUSETS
-       E(PROC_TID_CPUSET,     "cpuset",  S_IFREG|S_IRUGO),
+       REG("cpuset",    S_IRUGO, cpuset),
 #endif
-       E(PROC_TID_OOM_SCORE,  "oom_score",S_IFREG|S_IRUGO),
-       E(PROC_TID_OOM_ADJUST, "oom_adj", S_IFREG|S_IRUGO|S_IWUSR),
+       INF("oom_score", S_IRUGO, oom_score),
+       REG("oom_adj",   S_IRUGO|S_IWUSR, oom_adjust),
 #ifdef CONFIG_AUDITSYSCALL
-       E(PROC_TID_LOGINUID, "loginuid", S_IFREG|S_IWUSR|S_IRUGO),
+       REG("loginuid",  S_IWUSR|S_IRUGO, loginuid),
 #endif
-       {0,0,NULL,0}
 };
 
 static int proc_tid_base_readdir(struct file * filp,
@@ -2138,7 +2077,8 @@ static int proc_tid_base_readdir(struct file * filp,
 }
 
 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);
+       return proc_pident_lookup(dir, dentry,
+                                 tid_base_stuff, ARRAY_SIZE(tid_base_stuff));
 }
 
 static struct file_operations proc_tid_base_operations = {
@@ -2152,13 +2092,39 @@ static struct inode_operations proc_tid_base_inode_operations = {
        .setattr        = proc_setattr,
 };
 
-/* SMP-safe */
+static struct dentry *proc_task_instantiate(struct inode *dir,
+       struct dentry *dentry, struct task_struct *task, void *ptr)
+{
+       struct dentry *error = ERR_PTR(-ENOENT);
+       struct inode *inode;
+       inode = proc_pid_make_inode(dir->i_sb, task);
+
+       if (!inode)
+               goto out;
+       inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
+       inode->i_op = &proc_tid_base_inode_operations;
+       inode->i_fop = &proc_tid_base_operations;
+       inode->i_flags|=S_IMMUTABLE;
+       inode->i_nlink = 3;
+#ifdef CONFIG_SECURITY
+       inode->i_nlink += 1;
+#endif
+
+       dentry->d_op = &pid_dentry_operations;
+
+       d_add(dentry, inode);
+       /* Close the race of the process dying before we return the dentry */
+       if (pid_revalidate(dentry, NULL))
+               error = NULL;
+out:
+       return error;
+}
+
 static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
 {
        struct dentry *result = ERR_PTR(-ENOENT);
        struct task_struct *task;
        struct task_struct *leader = get_proc_task(dir);
-       struct inode *inode;
        unsigned tid;
 
        if (!leader)
@@ -2178,28 +2144,7 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry
        if (leader->tgid != task->tgid)
                goto out_drop_task;
 
-       inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_INO);
-
-
-       if (!inode)
-               goto out_drop_task;
-       inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
-       inode->i_op = &proc_tid_base_inode_operations;
-       inode->i_fop = &proc_tid_base_operations;
-       inode->i_flags|=S_IMMUTABLE;
-#ifdef CONFIG_SECURITY
-       inode->i_nlink = 4;
-#else
-       inode->i_nlink = 3;
-#endif
-
-       dentry->d_op = &pid_dentry_operations;
-
-       d_add(dentry, inode);
-       /* Close the race of the process dying before we return the dentry */
-       if (pid_revalidate(dentry, NULL))
-               result = NULL;
-
+       result = proc_task_instantiate(dir, dentry, task, NULL);
 out_drop_task:
        put_task_struct(task);
 out:
@@ -2277,10 +2222,18 @@ static struct task_struct *next_tid(struct task_struct *start)
        return pos;
 }
 
+static int proc_task_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+       struct task_struct *task, int tid)
+{
+       char name[PROC_NUMBUF];
+       int len = snprintf(name, sizeof(name), "%d", tid);
+       return proc_fill_cache(filp, dirent, filldir, name, len,
+                               proc_task_instantiate, task, NULL);
+}
+
 /* for the /proc/TGID/task/ directories */
 static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
-       char buf[PROC_NUMBUF];
        struct dentry *dentry = filp->f_dentry;
        struct inode *inode = dentry->d_inode;
        struct task_struct *leader = get_proc_task(inode);
@@ -2317,11 +2270,8 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi
        for (task = first_tid(leader, tid, pos - 2);
             task;
             task = next_tid(task), pos++) {
-               int len;
                tid = task->pid;
-               len = snprintf(buf, sizeof(buf), "%d", tid);
-               ino = fake_ino(tid, PROC_TID_INO);
-               if (filldir(dirent, buf, len, pos, ino, DT_DIR < 0)) {
+               if (proc_task_fill_cache(filp, dirent, filldir, task, tid) < 0) {
                        /* returning this tgid failed, save it as the first
                         * pid for the next readir call */
                        filp->f_version = tid;