procfs: Move /proc/pid/fd[info] handling code to fd.[ch]
authorCyrill Gorcunov <gorcunov@openvz.org>
Thu, 23 Aug 2012 10:43:24 +0000 (14:43 +0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 27 Sep 2012 01:10:01 +0000 (21:10 -0400)
This patch prepares the ground for further extension of
/proc/pid/fd[info] handling code by moving fdinfo handling
code into fs/proc/fd.c.

I think such move makes both fs/proc/base.c and fs/proc/fd.c
easier to read.

Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
Acked-by: Pavel Emelyanov <xemul@parallels.com>
CC: Al Viro <viro@ZenIV.linux.org.uk>
CC: Alexey Dobriyan <adobriyan@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: James Bottomley <jbottomley@parallels.com>
CC: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
CC: Alexey Dobriyan <adobriyan@gmail.com>
CC: Matthew Helsley <matt.helsley@gmail.com>
CC: "J. Bruce Fields" <bfields@fieldses.org>
CC: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/proc/Makefile
fs/proc/base.c
fs/proc/fd.c [new file with mode: 0644]
fs/proc/fd.h [new file with mode: 0644]
fs/proc/internal.h

index c1c729335924803f92e5530d4197b1eb3bd4907c..99349efbbc2b53781afd3e321a9a52cd92441882 100644 (file)
@@ -8,7 +8,7 @@ proc-y                  := nommu.o task_nommu.o
 proc-$(CONFIG_MMU)     := mmu.o task_mmu.o
 
 proc-y       += inode.o root.o base.o generic.o array.o \
-               proc_tty.o
+               proc_tty.o fd.o
 proc-y += cmdline.o
 proc-y += consoles.o
 proc-y += cpuinfo.o
index 1b6c84cbdb732e5684ccaa823548b8780cf1c16d..b55c3bb298e365e296f18eb76f898f793c037cb2 100644 (file)
@@ -90,6 +90,7 @@
 #endif
 #include <trace/events/oom.h>
 #include "internal.h"
+#include "fd.h"
 
 /* NOTE:
  *     Implementing inode permission operations in /proc is almost
@@ -136,8 +137,6 @@ struct pid_entry {
                NULL, &proc_single_file_operations,     \
                { .proc_show = show } )
 
-static int proc_fd_permission(struct inode *inode, int mask);
-
 /*
  * Count the number of hardlinks for the pid_entry table, excluding the .
  * and .. links.
@@ -1492,7 +1491,7 @@ out:
        return error;
 }
 
-static const struct inode_operations proc_pid_link_inode_operations = {
+const struct inode_operations proc_pid_link_inode_operations = {
        .readlink       = proc_pid_readlink,
        .follow_link    = proc_pid_follow_link,
        .setattr        = proc_setattr,
@@ -1501,21 +1500,6 @@ static const struct inode_operations proc_pid_link_inode_operations = {
 
 /* building an inode */
 
-static int task_dumpable(struct task_struct *task)
-{
-       int dumpable = 0;
-       struct mm_struct *mm;
-
-       task_lock(task);
-       mm = task->mm;
-       if (mm)
-               dumpable = get_dumpable(mm);
-       task_unlock(task);
-       if(dumpable == 1)
-               return 1;
-       return 0;
-}
-
 struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task)
 {
        struct inode * inode;
@@ -1641,15 +1625,6 @@ int pid_revalidate(struct dentry *dentry, unsigned int flags)
        return 0;
 }
 
-static int pid_delete_dentry(const struct dentry * dentry)
-{
-       /* Is the task we represent dead?
-        * If so, then don't put the dentry on the lru list,
-        * kill it immediately.
-        */
-       return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first;
-}
-
 const struct dentry_operations pid_dentry_operations =
 {
        .d_revalidate   = pid_revalidate,
@@ -1712,289 +1687,6 @@ end_instantiate:
        return filldir(dirent, name, len, filp->f_pos, ino, type);
 }
 
-static unsigned name_to_int(struct dentry *dentry)
-{
-       const char *name = dentry->d_name.name;
-       int len = dentry->d_name.len;
-       unsigned n = 0;
-
-       if (len > 1 && *name == '0')
-               goto out;
-       while (len-- > 0) {
-               unsigned c = *name++ - '0';
-               if (c > 9)
-                       goto out;
-               if (n >= (~0U-9)/10)
-                       goto out;
-               n *= 10;
-               n += c;
-       }
-       return n;
-out:
-       return ~0U;
-}
-
-#define PROC_FDINFO_MAX 64
-
-static int proc_fd_info(struct inode *inode, struct path *path, char *info)
-{
-       struct task_struct *task = get_proc_task(inode);
-       struct files_struct *files = NULL;
-       struct file *file;
-       int fd = proc_fd(inode);
-
-       if (task) {
-               files = get_files_struct(task);
-               put_task_struct(task);
-       }
-       if (files) {
-               /*
-                * We are not taking a ref to the file structure, so we must
-                * hold ->file_lock.
-                */
-               spin_lock(&files->file_lock);
-               file = fcheck_files(files, fd);
-               if (file) {
-                       unsigned int f_flags;
-                       struct fdtable *fdt;
-
-                       fdt = files_fdtable(files);
-                       f_flags = file->f_flags & ~O_CLOEXEC;
-                       if (close_on_exec(fd, fdt))
-                               f_flags |= O_CLOEXEC;
-
-                       if (path) {
-                               *path = file->f_path;
-                               path_get(&file->f_path);
-                       }
-                       if (info)
-                               snprintf(info, PROC_FDINFO_MAX,
-                                        "pos:\t%lli\n"
-                                        "flags:\t0%o\n",
-                                        (long long) file->f_pos,
-                                        f_flags);
-                       spin_unlock(&files->file_lock);
-                       put_files_struct(files);
-                       return 0;
-               }
-               spin_unlock(&files->file_lock);
-               put_files_struct(files);
-       }
-       return -ENOENT;
-}
-
-static int proc_fd_link(struct dentry *dentry, struct path *path)
-{
-       return proc_fd_info(dentry->d_inode, path, NULL);
-}
-
-static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)
-{
-       struct inode *inode;
-       struct task_struct *task;
-       int fd;
-       struct files_struct *files;
-       const struct cred *cred;
-
-       if (flags & LOOKUP_RCU)
-               return -ECHILD;
-
-       inode = dentry->d_inode;
-       task = get_proc_task(inode);
-       fd = proc_fd(inode);
-
-       if (task) {
-               files = get_files_struct(task);
-               if (files) {
-                       struct file *file;
-                       rcu_read_lock();
-                       file = fcheck_files(files, fd);
-                       if (file) {
-                               unsigned f_mode = file->f_mode;
-
-                               rcu_read_unlock();
-                               put_files_struct(files);
-
-                               if (task_dumpable(task)) {
-                                       rcu_read_lock();
-                                       cred = __task_cred(task);
-                                       inode->i_uid = cred->euid;
-                                       inode->i_gid = cred->egid;
-                                       rcu_read_unlock();
-                               } else {
-                                       inode->i_uid = GLOBAL_ROOT_UID;
-                                       inode->i_gid = GLOBAL_ROOT_GID;
-                               }
-
-                               if (S_ISLNK(inode->i_mode)) {
-                                       unsigned i_mode = S_IFLNK;
-                                       if (f_mode & FMODE_READ)
-                                               i_mode |= S_IRUSR | S_IXUSR;
-                                       if (f_mode & FMODE_WRITE)
-                                               i_mode |= S_IWUSR | S_IXUSR;
-                                       inode->i_mode = i_mode;
-                               }
-
-                               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 const 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, const void *ptr)
-{
-       unsigned fd = (unsigned long)ptr;
-       struct inode *inode;
-       struct proc_inode *ei;
-       struct dentry *error = ERR_PTR(-ENOENT);
-
-       inode = proc_pid_make_inode(dir->i_sb, task);
-       if (!inode)
-               goto out;
-       ei = PROC_I(inode);
-       ei->fd = fd;
-
-       inode->i_mode = S_IFLNK;
-       inode->i_op = &proc_pid_link_inode_operations;
-       inode->i_size = 64;
-       ei->op.proc_get_link = proc_fd_link;
-       d_set_d_op(dentry, &tid_fd_dentry_operations);
-       d_add(dentry, inode);
-       /* Close the race of the process dying before we return the dentry */
-       if (tid_fd_revalidate(dentry, 0))
-               error = NULL;
-
- out:
-       return error;
-}
-
-static struct dentry *proc_lookupfd_common(struct inode *dir,
-                                          struct dentry *dentry,
-                                          instantiate_t instantiate)
-{
-       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 = instantiate(dir, dentry, task, (void *)(unsigned long)fd);
-out:
-       put_task_struct(task);
-out_no_task:
-       return result;
-}
-
-static int proc_readfd_common(struct file * filp, void * dirent,
-                             filldir_t filldir, instantiate_t instantiate)
-{
-       struct dentry *dentry = filp->f_path.dentry;
-       struct inode *inode = dentry->d_inode;
-       struct task_struct *p = get_proc_task(inode);
-       unsigned int fd, ino;
-       int retval;
-       struct files_struct * files;
-
-       retval = -ENOENT;
-       if (!p)
-               goto out_no_task;
-       retval = 0;
-
-       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();
-                       for (fd = filp->f_pos-2;
-                            fd < files_fdtable(files)->max_fds;
-                            fd++, filp->f_pos++) {
-                               char name[PROC_NUMBUF];
-                               int len;
-                               int rv;
-
-                               if (!fcheck_files(files, fd))
-                                       continue;
-                               rcu_read_unlock();
-
-                               len = snprintf(name, sizeof(name), "%d", fd);
-                               rv = proc_fill_cache(filp, dirent, filldir,
-                                                    name, len, instantiate, p,
-                                                    (void *)(unsigned long)fd);
-                               if (rv < 0)
-                                       goto out_fd_loop;
-                               rcu_read_lock();
-                       }
-                       rcu_read_unlock();
-out_fd_loop:
-                       put_files_struct(files);
-       }
-out:
-       put_task_struct(p);
-out_no_task:
-       return retval;
-}
-
-static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry,
-                                   unsigned int flags)
-{
-       return proc_lookupfd_common(dir, dentry, proc_fd_instantiate);
-}
-
-static int proc_readfd(struct file *filp, void *dirent, filldir_t filldir)
-{
-       return proc_readfd_common(filp, dirent, filldir, proc_fd_instantiate);
-}
-
-static ssize_t proc_fdinfo_read(struct file *file, char __user *buf,
-                                     size_t len, loff_t *ppos)
-{
-       char tmp[PROC_FDINFO_MAX];
-       int err = proc_fd_info(file->f_path.dentry->d_inode, NULL, tmp);
-       if (!err)
-               err = simple_read_from_buffer(buf, len, ppos, tmp, strlen(tmp));
-       return err;
-}
-
-static const struct file_operations proc_fdinfo_file_operations = {
-       .open           = nonseekable_open,
-       .read           = proc_fdinfo_read,
-       .llseek         = no_llseek,
-};
-
-static const struct file_operations proc_fd_operations = {
-       .read           = generic_read_dir,
-       .readdir        = proc_readfd,
-       .llseek         = default_llseek,
-};
-
 #ifdef CONFIG_CHECKPOINT_RESTORE
 
 /*
@@ -2337,82 +2029,6 @@ static const struct file_operations proc_map_files_operations = {
 
 #endif /* CONFIG_CHECKPOINT_RESTORE */
 
-/*
- * /proc/pid/fd needs a special permission handler so that a process can still
- * access /proc/self/fd after it has executed a setuid().
- */
-static int proc_fd_permission(struct inode *inode, int mask)
-{
-       int rv = generic_permission(inode, mask);
-       if (rv == 0)
-               return 0;
-       if (task_pid(current) == proc_pid(inode))
-               rv = 0;
-       return rv;
-}
-
-/*
- * proc directories can do almost nothing..
- */
-static const struct inode_operations proc_fd_inode_operations = {
-       .lookup         = proc_lookupfd,
-       .permission     = proc_fd_permission,
-       .setattr        = proc_setattr,
-};
-
-static struct dentry *proc_fdinfo_instantiate(struct inode *dir,
-       struct dentry *dentry, struct task_struct *task, const void *ptr)
-{
-       unsigned fd = (unsigned long)ptr;
-       struct inode *inode;
-       struct proc_inode *ei;
-       struct dentry *error = ERR_PTR(-ENOENT);
-
-       inode = proc_pid_make_inode(dir->i_sb, task);
-       if (!inode)
-               goto out;
-       ei = PROC_I(inode);
-       ei->fd = fd;
-       inode->i_mode = S_IFREG | S_IRUSR;
-       inode->i_fop = &proc_fdinfo_file_operations;
-       d_set_d_op(dentry, &tid_fd_dentry_operations);
-       d_add(dentry, inode);
-       /* Close the race of the process dying before we return the dentry */
-       if (tid_fd_revalidate(dentry, 0))
-               error = NULL;
-
- out:
-       return error;
-}
-
-static struct dentry *proc_lookupfdinfo(struct inode *dir,
-                                       struct dentry *dentry,
-                                       unsigned int flags)
-{
-       return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate);
-}
-
-static int proc_readfdinfo(struct file *filp, void *dirent, filldir_t filldir)
-{
-       return proc_readfd_common(filp, dirent, filldir,
-                                 proc_fdinfo_instantiate);
-}
-
-static const struct file_operations proc_fdinfo_operations = {
-       .read           = generic_read_dir,
-       .readdir        = proc_readfdinfo,
-       .llseek         = default_llseek,
-};
-
-/*
- * proc directories can do almost nothing..
- */
-static const struct inode_operations proc_fdinfo_inode_operations = {
-       .lookup         = proc_lookupfdinfo,
-       .setattr        = proc_setattr,
-};
-
-
 static struct dentry *proc_pident_instantiate(struct inode *dir,
        struct dentry *dentry, struct task_struct *task, const void *ptr)
 {
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
new file mode 100644 (file)
index 0000000..1b0f932
--- /dev/null
@@ -0,0 +1,351 @@
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/dcache.h>
+#include <linux/path.h>
+#include <linux/fdtable.h>
+#include <linux/namei.h>
+#include <linux/pid.h>
+#include <linux/security.h>
+
+#include <linux/proc_fs.h>
+
+#include "internal.h"
+#include "fd.h"
+
+#define PROC_FDINFO_MAX 64
+
+static int proc_fd_info(struct inode *inode, struct path *path, char *info)
+{
+       struct task_struct *task = get_proc_task(inode);
+       struct files_struct *files = NULL;
+       int fd = proc_fd(inode);
+       struct file *file;
+
+       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) {
+                       unsigned int f_flags;
+                       struct fdtable *fdt;
+
+                       fdt = files_fdtable(files);
+                       f_flags = file->f_flags & ~O_CLOEXEC;
+                       if (close_on_exec(fd, fdt))
+                               f_flags |= O_CLOEXEC;
+
+                       if (path) {
+                               *path = file->f_path;
+                               path_get(&file->f_path);
+                       }
+                       if (info)
+                               snprintf(info, PROC_FDINFO_MAX,
+                                        "pos:\t%lli\n"
+                                        "flags:\t0%o\n",
+                                        (long long) file->f_pos,
+                                        f_flags);
+                       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, unsigned int flags)
+{
+       struct files_struct *files;
+       struct task_struct *task;
+       const struct cred *cred;
+       struct inode *inode;
+       int fd;
+
+       if (flags & LOOKUP_RCU)
+               return -ECHILD;
+
+       inode = dentry->d_inode;
+       task = get_proc_task(inode);
+       fd = proc_fd(inode);
+
+       if (task) {
+               files = get_files_struct(task);
+               if (files) {
+                       struct file *file;
+
+                       rcu_read_lock();
+                       file = fcheck_files(files, fd);
+                       if (file) {
+                               unsigned f_mode = file->f_mode;
+
+                               rcu_read_unlock();
+                               put_files_struct(files);
+
+                               if (task_dumpable(task)) {
+                                       rcu_read_lock();
+                                       cred = __task_cred(task);
+                                       inode->i_uid = cred->euid;
+                                       inode->i_gid = cred->egid;
+                                       rcu_read_unlock();
+                               } else {
+                                       inode->i_uid = GLOBAL_ROOT_UID;
+                                       inode->i_gid = GLOBAL_ROOT_GID;
+                               }
+
+                               if (S_ISLNK(inode->i_mode)) {
+                                       unsigned i_mode = S_IFLNK;
+                                       if (f_mode & FMODE_READ)
+                                               i_mode |= S_IRUSR | S_IXUSR;
+                                       if (f_mode & FMODE_WRITE)
+                                               i_mode |= S_IWUSR | S_IXUSR;
+                                       inode->i_mode = i_mode;
+                               }
+
+                               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 const struct dentry_operations tid_fd_dentry_operations = {
+       .d_revalidate   = tid_fd_revalidate,
+       .d_delete       = pid_delete_dentry,
+};
+
+static int proc_fd_link(struct dentry *dentry, struct path *path)
+{
+       return proc_fd_info(dentry->d_inode, path, NULL);
+}
+
+static struct dentry *
+proc_fd_instantiate(struct inode *dir, struct dentry *dentry,
+                   struct task_struct *task, const void *ptr)
+{
+       struct dentry *error = ERR_PTR(-ENOENT);
+       unsigned fd = (unsigned long)ptr;
+       struct proc_inode *ei;
+       struct inode *inode;
+
+       inode = proc_pid_make_inode(dir->i_sb, task);
+       if (!inode)
+               goto out;
+
+       ei = PROC_I(inode);
+       ei->fd = fd;
+
+       inode->i_mode = S_IFLNK;
+       inode->i_op = &proc_pid_link_inode_operations;
+       inode->i_size = 64;
+
+       ei->op.proc_get_link = proc_fd_link;
+
+       d_set_d_op(dentry, &tid_fd_dentry_operations);
+       d_add(dentry, inode);
+
+       /* Close the race of the process dying before we return the dentry */
+       if (tid_fd_revalidate(dentry, 0))
+               error = NULL;
+ out:
+       return error;
+}
+
+static struct dentry *proc_lookupfd_common(struct inode *dir,
+                                          struct dentry *dentry,
+                                          instantiate_t instantiate)
+{
+       struct task_struct *task = get_proc_task(dir);
+       struct dentry *result = ERR_PTR(-ENOENT);
+       unsigned fd = name_to_int(dentry);
+
+       if (!task)
+               goto out_no_task;
+       if (fd == ~0U)
+               goto out;
+
+       result = instantiate(dir, dentry, task, (void *)(unsigned long)fd);
+out:
+       put_task_struct(task);
+out_no_task:
+       return result;
+}
+
+static int proc_readfd_common(struct file * filp, void * dirent,
+                             filldir_t filldir, instantiate_t instantiate)
+{
+       struct dentry *dentry = filp->f_path.dentry;
+       struct inode *inode = dentry->d_inode;
+       struct task_struct *p = get_proc_task(inode);
+       struct files_struct *files;
+       unsigned int fd, ino;
+       int retval;
+
+       retval = -ENOENT;
+       if (!p)
+               goto out_no_task;
+       retval = 0;
+
+       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();
+                       for (fd = filp->f_pos - 2;
+                            fd < files_fdtable(files)->max_fds;
+                            fd++, filp->f_pos++) {
+                               char name[PROC_NUMBUF];
+                               int len;
+                               int rv;
+
+                               if (!fcheck_files(files, fd))
+                                       continue;
+                               rcu_read_unlock();
+
+                               len = snprintf(name, sizeof(name), "%d", fd);
+                               rv = proc_fill_cache(filp, dirent, filldir,
+                                                    name, len, instantiate, p,
+                                                    (void *)(unsigned long)fd);
+                               if (rv < 0)
+                                       goto out_fd_loop;
+                               rcu_read_lock();
+                       }
+                       rcu_read_unlock();
+out_fd_loop:
+                       put_files_struct(files);
+       }
+out:
+       put_task_struct(p);
+out_no_task:
+       return retval;
+}
+
+static ssize_t proc_fdinfo_read(struct file *file, char __user *buf,
+                               size_t len, loff_t *ppos)
+{
+       char tmp[PROC_FDINFO_MAX];
+       int err = proc_fd_info(file->f_path.dentry->d_inode, NULL, tmp);
+       if (!err)
+               err = simple_read_from_buffer(buf, len, ppos, tmp, strlen(tmp));
+       return err;
+}
+
+static const struct file_operations proc_fdinfo_file_operations = {
+       .open           = nonseekable_open,
+       .read           = proc_fdinfo_read,
+       .llseek         = no_llseek,
+};
+
+static int proc_readfd(struct file *filp, void *dirent, filldir_t filldir)
+{
+       return proc_readfd_common(filp, dirent, filldir, proc_fd_instantiate);
+}
+
+const struct file_operations proc_fd_operations = {
+       .read           = generic_read_dir,
+       .readdir        = proc_readfd,
+       .llseek         = default_llseek,
+};
+
+static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry,
+                                   unsigned int flags)
+{
+       return proc_lookupfd_common(dir, dentry, proc_fd_instantiate);
+}
+
+/*
+ * /proc/pid/fd needs a special permission handler so that a process can still
+ * access /proc/self/fd after it has executed a setuid().
+ */
+int proc_fd_permission(struct inode *inode, int mask)
+{
+       int rv = generic_permission(inode, mask);
+       if (rv == 0)
+               return 0;
+       if (task_pid(current) == proc_pid(inode))
+               rv = 0;
+       return rv;
+}
+
+const struct inode_operations proc_fd_inode_operations = {
+       .lookup         = proc_lookupfd,
+       .permission     = proc_fd_permission,
+       .setattr        = proc_setattr,
+};
+
+static struct dentry *
+proc_fdinfo_instantiate(struct inode *dir, struct dentry *dentry,
+                       struct task_struct *task, const void *ptr)
+{
+       struct dentry *error = ERR_PTR(-ENOENT);
+       unsigned fd = (unsigned long)ptr;
+       struct proc_inode *ei;
+       struct inode *inode;
+
+       inode = proc_pid_make_inode(dir->i_sb, task);
+       if (!inode)
+               goto out;
+
+       ei = PROC_I(inode);
+       ei->fd = fd;
+
+       inode->i_mode = S_IFREG | S_IRUSR;
+       inode->i_fop = &proc_fdinfo_file_operations;
+
+       d_set_d_op(dentry, &tid_fd_dentry_operations);
+       d_add(dentry, inode);
+
+       /* Close the race of the process dying before we return the dentry */
+       if (tid_fd_revalidate(dentry, 0))
+               error = NULL;
+ out:
+       return error;
+}
+
+static struct dentry *
+proc_lookupfdinfo(struct inode *dir, struct dentry *dentry, unsigned int flags)
+{
+       return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate);
+}
+
+static int proc_readfdinfo(struct file *filp, void *dirent, filldir_t filldir)
+{
+       return proc_readfd_common(filp, dirent, filldir,
+                                 proc_fdinfo_instantiate);
+}
+
+const struct inode_operations proc_fdinfo_inode_operations = {
+       .lookup         = proc_lookupfdinfo,
+       .setattr        = proc_setattr,
+};
+
+const struct file_operations proc_fdinfo_operations = {
+       .read           = generic_read_dir,
+       .readdir        = proc_readfdinfo,
+       .llseek         = default_llseek,
+};
diff --git a/fs/proc/fd.h b/fs/proc/fd.h
new file mode 100644 (file)
index 0000000..cbb1d47
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __PROCFS_FD_H__
+#define __PROCFS_FD_H__
+
+#include <linux/fs.h>
+
+extern const struct file_operations proc_fd_operations;
+extern const struct inode_operations proc_fd_inode_operations;
+
+extern const struct file_operations proc_fdinfo_operations;
+extern const struct inode_operations proc_fdinfo_inode_operations;
+
+extern int proc_fd_permission(struct inode *inode, int mask);
+
+#endif /* __PROCFS_FD_H__ */
index e1167a1c9126ee5f6a91971fec50ff3eaa79cce4..67925a7bd8cb757f56db940efcff1fe9c7ef112a 100644 (file)
@@ -9,6 +9,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 
+#include <linux/sched.h>
 #include <linux/proc_fs.h>
 struct  ctl_table_header;
 
@@ -65,6 +66,7 @@ extern const struct file_operations proc_clear_refs_operations;
 extern const struct file_operations proc_pagemap_operations;
 extern const struct file_operations proc_net_operations;
 extern const struct inode_operations proc_net_inode_operations;
+extern const struct inode_operations proc_pid_link_inode_operations;
 
 struct proc_maps_private {
        struct pid *pid;
@@ -91,6 +93,52 @@ static inline int proc_fd(struct inode *inode)
        return PROC_I(inode)->fd;
 }
 
+static inline int task_dumpable(struct task_struct *task)
+{
+       int dumpable = 0;
+       struct mm_struct *mm;
+
+       task_lock(task);
+       mm = task->mm;
+       if (mm)
+               dumpable = get_dumpable(mm);
+       task_unlock(task);
+       if(dumpable == 1)
+               return 1;
+       return 0;
+}
+
+static inline int pid_delete_dentry(const struct dentry * dentry)
+{
+       /* Is the task we represent dead?
+        * If so, then don't put the dentry on the lru list,
+        * kill it immediately.
+        */
+       return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first;
+}
+
+static inline unsigned name_to_int(struct dentry *dentry)
+{
+       const char *name = dentry->d_name.name;
+       int len = dentry->d_name.len;
+       unsigned n = 0;
+
+       if (len > 1 && *name == '0')
+               goto out;
+       while (len-- > 0) {
+               unsigned c = *name++ - '0';
+               if (c > 9)
+                       goto out;
+               if (n >= (~0U-9)/10)
+                       goto out;
+               n *= 10;
+               n += c;
+       }
+       return n;
+out:
+       return ~0U;
+}
+
 struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *ino,
                struct dentry *dentry);
 int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent,