]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - fs/proc/base.c
[PATCH] proc: Use pid_task instead of open coding it
[mirror_ubuntu-zesty-kernel.git] / fs / proc / base.c
index 7832efbd43a66bb684c340f73092b7e9f111a4ad..04e29f929a118f917ef26e25934a3917f8e43edb 100644 (file)
  *     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
 
 struct pid_entry {
-       int type;
        int len;
        char *name;
        mode_t mode;
@@ -200,8 +97,7 @@ struct pid_entry {
        union proc_op op;
 };
 
-#define NOD(TYPE, NAME, MODE, IOP, FOP, OP) {          \
-       .type = (TYPE),                                 \
+#define NOD(NAME, MODE, IOP, FOP, OP) {                        \
        .len  = sizeof(NAME) - 1,                       \
        .name = (NAME),                                 \
        .mode = MODE,                                   \
@@ -210,19 +106,19 @@ struct pid_entry {
        .op   = OP,                                     \
 }
 
-#define DIR(TYPE, NAME, MODE, OTYPE)                                           \
-       NOD(TYPE, NAME, (S_IFDIR|(MODE)),                                       \
+#define DIR(NAME, MODE, OTYPE)                                                 \
+       NOD(NAME, (S_IFDIR|(MODE)),                                             \
                &proc_##OTYPE##_inode_operations, &proc_##OTYPE##_operations,   \
                {} )
-#define LNK(TYPE, NAME, OTYPE)                                 \
-       NOD(TYPE, NAME, (S_IFLNK|S_IRWXUGO),                    \
+#define LNK(NAME, OTYPE)                                       \
+       NOD(NAME, (S_IFLNK|S_IRWXUGO),                          \
                &proc_pid_link_inode_operations, NULL,          \
                { .proc_get_link = &proc_##OTYPE##_link } )
-#define REG(TYPE, NAME, MODE, OTYPE)                   \
-       NOD(TYPE, NAME, (S_IFREG|(MODE)), NULL,         \
+#define REG(NAME, MODE, OTYPE)                         \
+       NOD(NAME, (S_IFREG|(MODE)), NULL,               \
                &proc_##OTYPE##_operations, {})
-#define INF(TYPE, NAME, MODE, OTYPE)                   \
-       NOD(TYPE, NAME, (S_IFREG|(MODE)),               \
+#define INF(NAME, MODE, OTYPE)                         \
+       NOD(NAME, (S_IFREG|(MODE)),                     \
                NULL, &proc_info_file_operations,       \
                { .proc_read = &proc_##OTYPE } )
 
@@ -1043,7 +939,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;
@@ -1057,13 +953,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_pid(task_pid(task));
        if (!ei->pid)
                goto out_unlock;
 
@@ -1160,6 +1055,50 @@ static struct dentry_operations pid_dentry_operations =
 
 /* Lookups */
 
+typedef struct dentry *instantiate_t(struct inode *, struct dentry *, struct task_struct *, void *);
+
+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;
@@ -1254,30 +1193,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;
 
        /*
@@ -1287,13 +1220,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;
@@ -1301,20 +1235,46 @@ 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;
 }
 
+/* SMP-safe */
+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;
@@ -1322,7 +1282,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;
 
@@ -1352,22 +1311,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;
                                }
@@ -1395,6 +1344,36 @@ static struct inode_operations proc_fd_inode_operations = {
        .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;
+}
+
 /* SMP-safe */
 static struct dentry *proc_pident_lookup(struct inode *dir, 
                                         struct dentry *dentry,
@@ -1404,7 +1383,6 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
        struct dentry *error;
        struct task_struct *task = get_proc_task(dir);
        struct pid_entry *p;
-       struct proc_inode *ei;
 
        error = ERR_PTR(-ENOENT);
        inode = NULL;
@@ -1425,31 +1403,20 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
        if (!p->name)
                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;
-       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;
+       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)
@@ -1465,11 +1432,10 @@ static int proc_pident_readdir(struct file *filp,
 
        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:
@@ -1494,8 +1460,7 @@ static int proc_pident_readdir(struct file *filp,
                }
                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)
+                       if (proc_pident_fill_cache(filp, dirent, filldir, task, p) < 0)
                                goto out;
                        filp->f_pos++;
                        p++;
@@ -1504,6 +1469,8 @@ static int proc_pident_readdir(struct file *filp,
 
        ret = 1;
 out:
+       put_task_struct(task);
+out_no_task:
        return ret;
 }
 
@@ -1582,72 +1549,40 @@ static struct file_operations proc_pid_attr_operations = {
        .write          = proc_pid_attr_write,
 };
 
-static struct pid_entry tgid_attr_stuff[] = {
-       REG(PROC_TGID_ATTR_CURRENT,    "current",    S_IRUGO|S_IWUGO, pid_attr),
-       REG(PROC_TGID_ATTR_PREV,       "prev",       S_IRUGO,         pid_attr),
-       REG(PROC_TGID_ATTR_EXEC,       "exec",       S_IRUGO|S_IWUGO, pid_attr),
-       REG(PROC_TGID_ATTR_FSCREATE,   "fscreate",   S_IRUGO|S_IWUGO, pid_attr),
-       REG(PROC_TGID_ATTR_KEYCREATE,  "keycreate",  S_IRUGO|S_IWUGO, pid_attr),
-       REG(PROC_TGID_ATTR_SOCKCREATE, "sockcreate", S_IRUGO|S_IWUGO, pid_attr),
-       {}
-};
-static struct pid_entry tid_attr_stuff[] = {
-       REG(PROC_TID_ATTR_CURRENT,    "current",    S_IRUGO|S_IWUGO, pid_attr),
-       REG(PROC_TID_ATTR_PREV,       "prev",       S_IRUGO,         pid_attr),
-       REG(PROC_TID_ATTR_EXEC,       "exec",       S_IRUGO|S_IWUGO, pid_attr),
-       REG(PROC_TID_ATTR_FSCREATE,   "fscreate",   S_IRUGO|S_IWUGO, pid_attr),
-       REG(PROC_TID_ATTR_KEYCREATE,  "keycreate",  S_IRUGO|S_IWUGO, pid_attr),
-       REG(PROC_TID_ATTR_SOCKCREATE, "sockcreate", S_IRUGO|S_IWUGO, pid_attr),
+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,
+static int proc_attr_dir_readdir(struct file * filp,
                             void * dirent, filldir_t filldir)
 {
        return proc_pident_readdir(filp,dirent,filldir,
-                                  tgid_attr_stuff,ARRAY_SIZE(tgid_attr_stuff));
+                                  attr_dir_stuff,ARRAY_SIZE(attr_dir_stuff));
 }
 
-static int proc_tid_attr_readdir(struct file * filp,
-                            void * dirent, filldir_t filldir)
-{
-       return proc_pident_readdir(filp,dirent,filldir,
-                                  tid_attr_stuff,ARRAY_SIZE(tid_attr_stuff));
-}
-
-static struct file_operations proc_tgid_attr_operations = {
+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,
-                               struct dentry *dentry, struct nameidata *nd)
-{
-       return proc_pident_lookup(dir, dentry, tgid_attr_stuff);
-}
-
-static struct dentry *proc_tid_attr_lookup(struct inode *dir,
+static struct dentry *proc_attr_dir_lookup(struct inode *dir,
                                struct dentry *dentry, struct nameidata *nd)
 {
-       return proc_pident_lookup(dir, dentry, tid_attr_stuff);
+       return proc_pident_lookup(dir, dentry, attr_dir_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
 
 /*
@@ -1681,7 +1616,7 @@ static struct inode_operations proc_self_inode_operations = {
  * describe something that is process related.
  */
 static struct pid_entry proc_base_stuff[] = {
-       NOD(PROC_TGID_INO,      "self", S_IFLNK|S_IRWXUGO,
+       NOD("self", S_IFLNK|S_IRWXUGO,
                &proc_self_inode_operations, NULL, {}),
        {}
 };
@@ -1709,29 +1644,13 @@ static struct dentry_operations proc_base_dentry_operations =
        .d_delete       = pid_delete_dentry,
 };
 
-static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
+static struct dentry *proc_base_instantiate(struct inode *dir,
+       struct dentry *dentry, struct task_struct *task, void *ptr)
 {
+       struct pid_entry *p = ptr;
        struct inode *inode;
-       struct dentry *error;
-       struct task_struct *task = get_proc_task(dir);
-       struct pid_entry *p;
        struct proc_inode *ei;
-
-       error = ERR_PTR(-ENOENT);
-       inode = NULL;
-
-       if (!task)
-               goto out_no_task;
-
-       /* Lookup the directory entry */
-       for (p = proc_base_stuff; p->name; p++) {
-               if (p->len != dentry->d_name.len)
-                       continue;
-               if (!memcmp(dentry->d_name.name, p->name, p->len))
-                       break;
-       }
-       if (!p->name)
-               goto out;
+       struct dentry *error = ERR_PTR(-EINVAL);
 
        /* Allocate the inode */
        error = ERR_PTR(-ENOMEM);
@@ -1742,7 +1661,6 @@ static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
        /* Initialize the inode */
        ei = PROC_I(inode);
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-       inode->i_ino = fake_ino(0, p->type);
 
        /*
         * grab the reference to the task.
@@ -1767,14 +1685,48 @@ static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
        d_add(dentry, inode);
        error = NULL;
 out:
-       put_task_struct(task);
-out_no_task:
        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;
+
+       error = ERR_PTR(-ENOENT);
+
+       if (!task)
+               goto out_no_task;
+
+       /* Lookup the directory entry */
+       for (p = proc_base_stuff; p->name; p++) {
+               if (p->len != dentry->d_name.len)
+                       continue;
+               if (!memcmp(dentry->d_name.name, p->name, p->len))
+                       break;
+       }
+       if (!p->name)
+               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
  */
@@ -1782,46 +1734,46 @@ static struct file_operations proc_task_operations;
 static struct inode_operations proc_task_inode_operations;
 
 static struct pid_entry tgid_base_stuff[] = {
-       DIR(PROC_TGID_TASK,       "task",       S_IRUGO|S_IXUGO, task),
-       DIR(PROC_TGID_FD,         "fd",         S_IRUSR|S_IXUSR, fd),
-       INF(PROC_TGID_ENVIRON,    "environ",    S_IRUSR, pid_environ),
-       INF(PROC_TGID_AUXV,       "auxv",       S_IRUSR, pid_auxv),
-       INF(PROC_TGID_STATUS,     "status",     S_IRUGO, pid_status),
-       INF(PROC_TGID_CMDLINE,    "cmdline",    S_IRUGO, pid_cmdline),
-       INF(PROC_TGID_STAT,       "stat",       S_IRUGO, tgid_stat),
-       INF(PROC_TGID_STATM,      "statm",      S_IRUGO, pid_statm),
-       REG(PROC_TGID_MAPS,       "maps",       S_IRUGO, maps),
+       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
-       REG(PROC_TGID_NUMA_MAPS,  "numa_maps",  S_IRUGO, numa_maps),
+       REG("numa_maps",  S_IRUGO, numa_maps),
 #endif
-       REG(PROC_TGID_MEM,        "mem",        S_IRUSR|S_IWUSR, mem),
+       REG("mem",        S_IRUSR|S_IWUSR, mem),
 #ifdef CONFIG_SECCOMP
-       REG(PROC_TGID_SECCOMP,    "seccomp",    S_IRUSR|S_IWUSR, seccomp),
+       REG("seccomp",    S_IRUSR|S_IWUSR, seccomp),
 #endif
-       LNK(PROC_TGID_CWD,        "cwd",        cwd),
-       LNK(PROC_TGID_ROOT,       "root",       root),
-       LNK(PROC_TGID_EXE,        "exe",        exe),
-       REG(PROC_TGID_MOUNTS,     "mounts",     S_IRUGO, mounts),
-       REG(PROC_TGID_MOUNTSTATS, "mountstats", S_IRUSR, mountstats),
+       LNK("cwd",        cwd),
+       LNK("root",       root),
+       LNK("exe",        exe),
+       REG("mounts",     S_IRUGO, mounts),
+       REG("mountstats", S_IRUSR, mountstats),
 #ifdef CONFIG_MMU
-       REG(PROC_TGID_SMAPS,      "smaps",      S_IRUGO, smaps),
+       REG("smaps",      S_IRUGO, smaps),
 #endif
 #ifdef CONFIG_SECURITY
-       DIR(PROC_TGID_ATTR,       "attr",       S_IRUGO|S_IXUGO, tgid_attr),
+       DIR("attr",       S_IRUGO|S_IXUGO, attr_dir),
 #endif
 #ifdef CONFIG_KALLSYMS
-       INF(PROC_TGID_WCHAN,      "wchan",      S_IRUGO, pid_wchan),
+       INF("wchan",      S_IRUGO, pid_wchan),
 #endif
 #ifdef CONFIG_SCHEDSTATS
-       INF(PROC_TGID_SCHEDSTAT,  "schedstat",  S_IRUGO, pid_schedstat),
+       INF("schedstat",  S_IRUGO, pid_schedstat),
 #endif
 #ifdef CONFIG_CPUSETS
-       REG(PROC_TGID_CPUSET,     "cpuset",     S_IRUGO, cpuset),
+       REG("cpuset",     S_IRUGO, cpuset),
 #endif
-       INF(PROC_TGID_OOM_SCORE,  "oom_score",  S_IRUGO, oom_score),
-       REG(PROC_TGID_OOM_ADJUST, "oom_adj",    S_IRUGO|S_IWUSR, oom_adjust),
+       INF("oom_score",  S_IRUGO, oom_score),
+       REG("oom_adj",    S_IRUGO|S_IWUSR, oom_adjust),
 #ifdef CONFIG_AUDITSYSCALL
-       REG(PROC_TGID_LOGINUID,   "loginuid",   S_IWUSR|S_IRUGO, loginuid),
+       REG("loginuid",   S_IWUSR|S_IRUGO, loginuid),
 #endif
        {}
 };
@@ -1915,12 +1867,40 @@ out:
        return;
 }
 
+struct dentry *proc_pid_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_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
+
+       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 */
 struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
 {
        struct dentry *result = ERR_PTR(-ENOENT);
        struct task_struct *task;
-       struct inode *inode;
        unsigned tgid;
 
        result = proc_base_lookup(dir, dentry);
@@ -1939,28 +1919,7 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct
        if (!task)
                goto out;
 
-       inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO);
-       if (!inode)
-               goto out_put_task;
-
-       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;
-#endif
-
-       dentry->d_op = &pid_dentry_operations;
-
-       d_add(dentry, inode);
-       /* Close the race of the process dying before we return the dentry */
-       if (pid_revalidate(dentry, NULL))
-               result = NULL;
-
-out_put_task:
+       result = proc_pid_instantiate(dir, dentry, task, NULL);
        put_task_struct(task);
 out:
        return result;
@@ -2004,18 +1963,29 @@ retry:
 
 #define TGID_OFFSET (FIRST_PROCESS_ENTRY + (1 /* /proc/self */))
 
+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 (!reaper)
+               goto out_no_task;
+
        for (; nr < (ARRAY_SIZE(proc_base_stuff) - 1); filp->f_pos++, nr++) {
                struct pid_entry *p = &proc_base_stuff[nr];
-               if (filldir(dirent, p->name, p->len, filp->f_pos,
-                           fake_ino(0, p->type), p->mode >> 12) < 0)
+               if (proc_base_fill_cache(filp, dirent, filldir, reaper, p) < 0)
                        goto out;
        }
 
@@ -2023,19 +1993,17 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
        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;
 }
 
@@ -2043,44 +2011,44 @@ out:
  * Tasks
  */
 static struct pid_entry tid_base_stuff[] = {
-       DIR(PROC_TID_FD,         "fd",        S_IRUSR|S_IXUSR, fd),
-       INF(PROC_TID_ENVIRON,    "environ",   S_IRUSR, pid_environ),
-       INF(PROC_TID_AUXV,       "auxv",      S_IRUSR, pid_auxv),
-       INF(PROC_TID_STATUS,     "status",    S_IRUGO, pid_status),
-       INF(PROC_TID_CMDLINE,    "cmdline",   S_IRUGO, pid_cmdline),
-       INF(PROC_TID_STAT,       "stat",      S_IRUGO, tid_stat),
-       INF(PROC_TID_STATM,      "statm",     S_IRUGO, pid_statm),
-       REG(PROC_TID_MAPS,       "maps",      S_IRUGO, maps),
+       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
-       REG(PROC_TID_NUMA_MAPS,  "numa_maps", S_IRUGO, numa_maps),
+       REG("numa_maps", S_IRUGO, numa_maps),
 #endif
-       REG(PROC_TID_MEM,        "mem",       S_IRUSR|S_IWUSR, mem),
+       REG("mem",       S_IRUSR|S_IWUSR, mem),
 #ifdef CONFIG_SECCOMP
-       REG(PROC_TID_SECCOMP,    "seccomp",   S_IRUSR|S_IWUSR, seccomp),
+       REG("seccomp",   S_IRUSR|S_IWUSR, seccomp),
 #endif
-       LNK(PROC_TID_CWD,        "cwd",       cwd),
-       LNK(PROC_TID_ROOT,       "root",      root),
-       LNK(PROC_TID_EXE,        "exe",       exe),
-       REG(PROC_TID_MOUNTS,     "mounts",    S_IRUGO, mounts),
+       LNK("cwd",       cwd),
+       LNK("root",      root),
+       LNK("exe",       exe),
+       REG("mounts",    S_IRUGO, mounts),
 #ifdef CONFIG_MMU
-       REG(PROC_TID_SMAPS,      "smaps",     S_IRUGO, smaps),
+       REG("smaps",     S_IRUGO, smaps),
 #endif
 #ifdef CONFIG_SECURITY
-       DIR(PROC_TID_ATTR,       "attr",      S_IRUGO|S_IXUGO, tid_attr),
+       DIR("attr",      S_IRUGO|S_IXUGO, attr_dir),
 #endif
 #ifdef CONFIG_KALLSYMS
-       INF(PROC_TID_WCHAN,      "wchan",     S_IRUGO, pid_wchan),
+       INF("wchan",     S_IRUGO, pid_wchan),
 #endif
 #ifdef CONFIG_SCHEDSTATS
-       INF(PROC_TID_SCHEDSTAT,  "schedstat", S_IRUGO, pid_schedstat),
+       INF("schedstat", S_IRUGO, pid_schedstat),
 #endif
 #ifdef CONFIG_CPUSETS
-       REG(PROC_TID_CPUSET,     "cpuset",    S_IRUGO, cpuset),
+       REG("cpuset",    S_IRUGO, cpuset),
 #endif
-       INF(PROC_TID_OOM_SCORE,  "oom_score", S_IRUGO, oom_score),
-       REG(PROC_TID_OOM_ADJUST, "oom_adj",   S_IRUGO|S_IWUSR, oom_adjust),
+       INF("oom_score", S_IRUGO, oom_score),
+       REG("oom_adj",   S_IRUGO|S_IWUSR, oom_adjust),
 #ifdef CONFIG_AUDITSYSCALL
-       REG(PROC_TID_LOGINUID,   "loginuid",  S_IWUSR|S_IRUGO, loginuid),
+       REG("loginuid",  S_IWUSR|S_IRUGO, loginuid),
 #endif
        {}
 };
@@ -2107,13 +2075,40 @@ static struct inode_operations proc_tid_base_inode_operations = {
        .setattr        = proc_setattr,
 };
 
+static struct dentry *proc_task_instantiate(struct inode *dir,
+       struct dentry *dentry, struct task_struct *task, void *ptr)
+{
+       struct dentry *error = ERR_PTR(-ENOENT);
+       struct inode *inode;
+       inode = proc_pid_make_inode(dir->i_sb, task);
+
+       if (!inode)
+               goto out;
+       inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
+       inode->i_op = &proc_tid_base_inode_operations;
+       inode->i_fop = &proc_tid_base_operations;
+       inode->i_flags|=S_IMMUTABLE;
+       inode->i_nlink = 3;
+#ifdef CONFIG_SECURITY
+       inode->i_nlink += 1;
+#endif
+
+       dentry->d_op = &pid_dentry_operations;
+
+       d_add(dentry, inode);
+       /* Close the race of the process dying before we return the dentry */
+       if (pid_revalidate(dentry, NULL))
+               error = NULL;
+out:
+       return error;
+}
+
 /* 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 = get_proc_task(dir);
-       struct inode *inode;
        unsigned tid;
 
        if (!leader)
@@ -2133,28 +2128,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:
@@ -2232,10 +2206,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);
@@ -2272,11 +2254,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;