OSDN Git Service

proc_lookupfd_common(): don't bother with instantiate unless the file is open
authorAl Viro <viro@zeniv.linux.org.uk>
Thu, 3 May 2018 02:42:22 +0000 (22:42 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Tue, 22 May 2018 18:28:04 +0000 (14:28 -0400)
... and take the "check if file is open, pick ->f_mode" into a helper;
tid_fd_revalidate() can use it.

The next patch will get rid of tid_fd_revalidate() calls in instantiate
callbacks.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/proc/fd.c

index 6b80cd1..d38845e 100644 (file)
@@ -81,12 +81,29 @@ static const struct file_operations proc_fdinfo_file_operations = {
        .release        = single_release,
 };
 
+static bool tid_fd_mode(struct task_struct *task, unsigned fd, fmode_t *mode)
+{
+       struct files_struct *files = get_files_struct(task);
+       struct file *file;
+
+       if (!files)
+               return false;
+
+       rcu_read_lock();
+       file = fcheck_files(files, fd);
+       if (file)
+               *mode = file->f_mode;
+       rcu_read_unlock();
+       put_files_struct(files);
+       return !!file;
+}
+
 static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)
 {
-       struct files_struct *files;
        struct task_struct *task;
        struct inode *inode;
        unsigned int fd;
+       fmode_t f_mode;
 
        if (flags & LOOKUP_RCU)
                return -ECHILD;
@@ -96,35 +113,20 @@ static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)
        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);
-
-                               task_dump_owner(task, 0, &inode->i_uid, &inode->i_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;
+               if (tid_fd_mode(task, fd, &f_mode)) {
+                       task_dump_owner(task, 0, &inode->i_uid, &inode->i_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;
                        }
-                       rcu_read_unlock();
-                       put_files_struct(files);
+                       security_task_to_inode(task, inode);
+                       put_task_struct(task);
+                       return 1;
                }
                put_task_struct(task);
        }
@@ -203,11 +205,14 @@ static struct dentry *proc_lookupfd_common(struct inode *dir,
        struct task_struct *task = get_proc_task(dir);
        int result = -ENOENT;
        unsigned fd = name_to_int(&dentry->d_name);
+       fmode_t f_mode;
 
        if (!task)
                goto out_no_task;
        if (fd == ~0U)
                goto out;
+       if (!tid_fd_mode(task, fd, &f_mode))
+               goto out;
 
        result = instantiate(dir, dentry, task, (void *)(unsigned long)fd);
 out: