summaryrefslogtreecommitdiff
path: root/fs/proc/fd.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2018-05-02 22:42:22 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2018-05-22 14:28:04 -0400
commit1ae9bd8b7e4912b238a14adc7c559a7ecbb9c062 (patch)
tree118b9f6c708060ea5286d46a879b5efd5c3a4ef7 /fs/proc/fd.c
parent1bbc55131e59bd099fdc568d3aa0b42634dbd188 (diff)
proc_lookupfd_common(): don't bother with instantiate unless the file is open
... 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>
Diffstat (limited to 'fs/proc/fd.c')
-rw-r--r--fs/proc/fd.c63
1 files changed, 34 insertions, 29 deletions
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 6b80cd1e419a..d38845ecc408 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -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: