don't bother with tid_fd_revalidate() in lookups
what we want it for is actually updating inode metadata; take _that_ into a separate helper and use it. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
1ae9bd8b7e
commit
9883638641
1 changed files with 44 additions and 37 deletions
81
fs/proc/fd.c
81
fs/proc/fd.c
|
@ -98,12 +98,27 @@ static bool tid_fd_mode(struct task_struct *task, unsigned fd, fmode_t *mode)
|
|||
return !!file;
|
||||
}
|
||||
|
||||
static void tid_fd_update_inode(struct task_struct *task, struct inode *inode,
|
||||
fmode_t 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;
|
||||
}
|
||||
security_task_to_inode(task, inode);
|
||||
}
|
||||
|
||||
static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct task_struct *task;
|
||||
struct inode *inode;
|
||||
unsigned int fd;
|
||||
fmode_t f_mode;
|
||||
|
||||
if (flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
|
@ -113,18 +128,9 @@ static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags)
|
|||
fd = proc_fd(inode);
|
||||
|
||||
if (task) {
|
||||
fmode_t f_mode;
|
||||
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;
|
||||
}
|
||||
security_task_to_inode(task, inode);
|
||||
tid_fd_update_inode(task, inode, f_mode);
|
||||
put_task_struct(task);
|
||||
return 1;
|
||||
}
|
||||
|
@ -168,34 +174,35 @@ static int proc_fd_link(struct dentry *dentry, struct path *path)
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct fd_data {
|
||||
fmode_t mode;
|
||||
unsigned fd;
|
||||
};
|
||||
|
||||
static int
|
||||
proc_fd_instantiate(struct inode *dir, struct dentry *dentry,
|
||||
struct task_struct *task, const void *ptr)
|
||||
{
|
||||
unsigned fd = (unsigned long)ptr;
|
||||
const struct fd_data *data = ptr;
|
||||
struct proc_inode *ei;
|
||||
struct inode *inode;
|
||||
|
||||
inode = proc_pid_make_inode(dir->i_sb, task, S_IFLNK);
|
||||
if (!inode)
|
||||
goto out;
|
||||
return -ENOENT;
|
||||
|
||||
ei = PROC_I(inode);
|
||||
ei->fd = fd;
|
||||
ei->fd = data->fd;
|
||||
|
||||
inode->i_op = &proc_pid_link_inode_operations;
|
||||
inode->i_size = 64;
|
||||
|
||||
ei->op.proc_get_link = proc_fd_link;
|
||||
tid_fd_update_inode(task, inode, data->mode);
|
||||
|
||||
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))
|
||||
return 0;
|
||||
out:
|
||||
return -ENOENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dentry *proc_lookupfd_common(struct inode *dir,
|
||||
|
@ -204,17 +211,16 @@ 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;
|
||||
struct fd_data data = {.fd = name_to_int(&dentry->d_name)};
|
||||
|
||||
if (!task)
|
||||
goto out_no_task;
|
||||
if (fd == ~0U)
|
||||
if (data.fd == ~0U)
|
||||
goto out;
|
||||
if (!tid_fd_mode(task, fd, &f_mode))
|
||||
if (!tid_fd_mode(task, data.fd, &data.mode))
|
||||
goto out;
|
||||
|
||||
result = instantiate(dir, dentry, task, (void *)(unsigned long)fd);
|
||||
result = instantiate(dir, dentry, task, &data);
|
||||
out:
|
||||
put_task_struct(task);
|
||||
out_no_task:
|
||||
|
@ -241,17 +247,22 @@ static int proc_readfd_common(struct file *file, struct dir_context *ctx,
|
|||
for (fd = ctx->pos - 2;
|
||||
fd < files_fdtable(files)->max_fds;
|
||||
fd++, ctx->pos++) {
|
||||
struct file *f;
|
||||
struct fd_data data;
|
||||
char name[10 + 1];
|
||||
int len;
|
||||
|
||||
if (!fcheck_files(files, fd))
|
||||
f = fcheck_files(files, fd);
|
||||
if (!f)
|
||||
continue;
|
||||
data.mode = f->f_mode;
|
||||
rcu_read_unlock();
|
||||
data.fd = fd;
|
||||
|
||||
len = snprintf(name, sizeof(name), "%u", fd);
|
||||
if (!proc_fill_cache(file, ctx,
|
||||
name, len, instantiate, p,
|
||||
(void *)(unsigned long)fd))
|
||||
&data))
|
||||
goto out_fd_loop;
|
||||
cond_resched();
|
||||
rcu_read_lock();
|
||||
|
@ -313,27 +324,23 @@ static int
|
|||
proc_fdinfo_instantiate(struct inode *dir, struct dentry *dentry,
|
||||
struct task_struct *task, const void *ptr)
|
||||
{
|
||||
unsigned fd = (unsigned long)ptr;
|
||||
const struct fd_data *data = ptr;
|
||||
struct proc_inode *ei;
|
||||
struct inode *inode;
|
||||
|
||||
inode = proc_pid_make_inode(dir->i_sb, task, S_IFREG | S_IRUSR);
|
||||
if (!inode)
|
||||
goto out;
|
||||
return -ENOENT;
|
||||
|
||||
ei = PROC_I(inode);
|
||||
ei->fd = fd;
|
||||
ei->fd = data->fd;
|
||||
|
||||
inode->i_fop = &proc_fdinfo_file_operations;
|
||||
tid_fd_update_inode(task, inode, 0);
|
||||
|
||||
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))
|
||||
return 0;
|
||||
out:
|
||||
return -ENOENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dentry *
|
||||
|
|
Loading…
Reference in a new issue