Skip to content

Commit

Permalink
add file position info to proc
Browse files Browse the repository at this point in the history
Add support for finding out the current file position, open flags and
possibly other info in the future.

These new entries are added:

  /proc/PID/fdinfo/FD
  /proc/PID/task/TID/fdinfo/FD

For each fd the information is provided in the following format:

pos:	1234
flags:	0100002

[bunk@stusta.de: make struct proc_fdinfo_file_operations static]
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Cc: Alexey Dobriyan <adobriyan@sw.ru>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Miklos Szeredi authored and Linus Torvalds committed May 8, 2007
1 parent c5141e6 commit 2793274
Showing 1 changed file with 114 additions and 18 deletions.
132 changes: 114 additions & 18 deletions fs/proc/base.c
Expand Up @@ -1238,7 +1238,10 @@ static unsigned name_to_int(struct dentry *dentry)
return ~0U; return ~0U;
} }


static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) #define PROC_FDINFO_MAX 64

static int proc_fd_info(struct inode *inode, struct dentry **dentry,
struct vfsmount **mnt, char *info)
{ {
struct task_struct *task = get_proc_task(inode); struct task_struct *task = get_proc_task(inode);
struct files_struct *files = NULL; struct files_struct *files = NULL;
Expand All @@ -1257,8 +1260,16 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm
spin_lock(&files->file_lock); spin_lock(&files->file_lock);
file = fcheck_files(files, fd); file = fcheck_files(files, fd);
if (file) { if (file) {
*mnt = mntget(file->f_path.mnt); if (mnt)
*dentry = dget(file->f_path.dentry); *mnt = mntget(file->f_path.mnt);
if (dentry)
*dentry = dget(file->f_path.dentry);
if (info)
snprintf(info, PROC_FDINFO_MAX,
"pos:\t%lli\n"
"flags:\t0%o\n",
(long long) file->f_pos,
file->f_flags);
spin_unlock(&files->file_lock); spin_unlock(&files->file_lock);
put_files_struct(files); put_files_struct(files);
return 0; return 0;
Expand All @@ -1269,6 +1280,12 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm
return -ENOENT; return -ENOENT;
} }


static int proc_fd_link(struct inode *inode, struct dentry **dentry,
struct vfsmount **mnt)
{
return proc_fd_info(inode, dentry, mnt, NULL);
}

static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
{ {
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
Expand Down Expand Up @@ -1364,7 +1381,9 @@ static struct dentry *proc_fd_instantiate(struct inode *dir,
goto out; goto out;
} }


static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd) static struct dentry *proc_lookupfd_common(struct inode *dir,
struct dentry *dentry,
instantiate_t instantiate)
{ {
struct task_struct *task = get_proc_task(dir); struct task_struct *task = get_proc_task(dir);
unsigned fd = name_to_int(dentry); unsigned fd = name_to_int(dentry);
Expand All @@ -1375,23 +1394,15 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
if (fd == ~0U) if (fd == ~0U)
goto out; goto out;


result = proc_fd_instantiate(dir, dentry, task, &fd); result = instantiate(dir, dentry, task, &fd);
out: out:
put_task_struct(task); put_task_struct(task);
out_no_task: out_no_task:
return result; return result;
} }


static int proc_fd_fill_cache(struct file *filp, void *dirent, filldir_t filldir, static int proc_readfd_common(struct file * filp, void * dirent,
struct task_struct *task, int fd) filldir_t filldir, instantiate_t instantiate)
{
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_path.dentry; struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode; struct inode *inode = dentry->d_inode;
Expand Down Expand Up @@ -1427,12 +1438,17 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
for (fd = filp->f_pos-2; for (fd = filp->f_pos-2;
fd < fdt->max_fds; fd < fdt->max_fds;
fd++, filp->f_pos++) { fd++, filp->f_pos++) {
char name[PROC_NUMBUF];
int len;


if (!fcheck_files(files, fd)) if (!fcheck_files(files, fd))
continue; continue;
rcu_read_unlock(); rcu_read_unlock();


if (proc_fd_fill_cache(filp, dirent, filldir, p, fd) < 0) { len = snprintf(name, sizeof(name), "%d", fd);
if (proc_fill_cache(filp, dirent, filldir,
name, len, instantiate,
p, &fd) < 0) {
rcu_read_lock(); rcu_read_lock();
break; break;
} }
Expand All @@ -1447,6 +1463,32 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
return retval; return retval;
} }


static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{
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, 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,
};

static const struct file_operations proc_fd_operations = { static const struct file_operations proc_fd_operations = {
.read = generic_read_dir, .read = generic_read_dir,
.readdir = proc_readfd, .readdir = proc_readfd,
Expand Down Expand Up @@ -1478,6 +1520,58 @@ static const struct inode_operations proc_fd_inode_operations = {
.setattr = proc_setattr, .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 *)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;
dentry->d_op = &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, NULL))
error = NULL;

out:
return error;
}

static struct dentry *proc_lookupfdinfo(struct inode *dir,
struct dentry *dentry,
struct nameidata *nd)
{
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,
};

/*
* 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, static struct dentry *proc_pident_instantiate(struct inode *dir,
struct dentry *dentry, struct task_struct *task, const void *ptr) struct dentry *dentry, struct task_struct *task, const void *ptr)
{ {
Expand Down Expand Up @@ -1888,6 +1982,7 @@ static const struct inode_operations proc_task_inode_operations;
static const struct pid_entry tgid_base_stuff[] = { static const struct pid_entry tgid_base_stuff[] = {
DIR("task", S_IRUGO|S_IXUGO, task), DIR("task", S_IRUGO|S_IXUGO, task),
DIR("fd", S_IRUSR|S_IXUSR, fd), DIR("fd", S_IRUSR|S_IXUSR, fd),
DIR("fdinfo", S_IRUSR|S_IXUSR, fdinfo),
INF("environ", S_IRUSR, pid_environ), INF("environ", S_IRUSR, pid_environ),
INF("auxv", S_IRUSR, pid_auxv), INF("auxv", S_IRUSR, pid_auxv),
INF("status", S_IRUGO, pid_status), INF("status", S_IRUGO, pid_status),
Expand Down Expand Up @@ -2041,7 +2136,7 @@ static struct dentry *proc_pid_instantiate(struct inode *dir,
inode->i_op = &proc_tgid_base_inode_operations; inode->i_op = &proc_tgid_base_inode_operations;
inode->i_fop = &proc_tgid_base_operations; inode->i_fop = &proc_tgid_base_operations;
inode->i_flags|=S_IMMUTABLE; inode->i_flags|=S_IMMUTABLE;
inode->i_nlink = 4; inode->i_nlink = 5;
#ifdef CONFIG_SECURITY #ifdef CONFIG_SECURITY
inode->i_nlink += 1; inode->i_nlink += 1;
#endif #endif
Expand Down Expand Up @@ -2171,6 +2266,7 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
*/ */
static const struct pid_entry tid_base_stuff[] = { static const struct pid_entry tid_base_stuff[] = {
DIR("fd", S_IRUSR|S_IXUSR, fd), DIR("fd", S_IRUSR|S_IXUSR, fd),
DIR("fdinfo", S_IRUSR|S_IXUSR, fdinfo),
INF("environ", S_IRUSR, pid_environ), INF("environ", S_IRUSR, pid_environ),
INF("auxv", S_IRUSR, pid_auxv), INF("auxv", S_IRUSR, pid_auxv),
INF("status", S_IRUGO, pid_status), INF("status", S_IRUGO, pid_status),
Expand Down Expand Up @@ -2251,7 +2347,7 @@ static struct dentry *proc_task_instantiate(struct inode *dir,
inode->i_op = &proc_tid_base_inode_operations; inode->i_op = &proc_tid_base_inode_operations;
inode->i_fop = &proc_tid_base_operations; inode->i_fop = &proc_tid_base_operations;
inode->i_flags|=S_IMMUTABLE; inode->i_flags|=S_IMMUTABLE;
inode->i_nlink = 3; inode->i_nlink = 4;
#ifdef CONFIG_SECURITY #ifdef CONFIG_SECURITY
inode->i_nlink += 1; inode->i_nlink += 1;
#endif #endif
Expand Down

0 comments on commit 2793274

Please sign in to comment.