* in /proc for a task before it execs a suid executable.
*/
-/*
- * For hysterical raisins we keep the same inumbers as in the old procfs.
- * Feel free to change the macro below - just keep the range distinct from
- * inumbers of the rest of procfs (currently those are in 0x0000--0xffff).
- * As soon as we'll get a separate superblock we will be able to forget
- * about magical ranges too.
- */
-
-#define fake_ino(pid,ino) (((pid)<<16)|(ino))
-
-enum pid_directory_inos {
- PROC_TGID_INO = 2,
- PROC_TGID_TASK,
- PROC_TGID_STATUS,
- PROC_TGID_MEM,
-#ifdef CONFIG_SECCOMP
- PROC_TGID_SECCOMP,
-#endif
- PROC_TGID_CWD,
- PROC_TGID_ROOT,
- PROC_TGID_EXE,
- PROC_TGID_FD,
- PROC_TGID_ENVIRON,
- PROC_TGID_AUXV,
- PROC_TGID_CMDLINE,
- PROC_TGID_STAT,
- PROC_TGID_STATM,
- PROC_TGID_MAPS,
- PROC_TGID_NUMA_MAPS,
- PROC_TGID_MOUNTS,
- PROC_TGID_MOUNTSTATS,
- PROC_TGID_WCHAN,
-#ifdef CONFIG_MMU
- PROC_TGID_SMAPS,
-#endif
-#ifdef CONFIG_SCHEDSTATS
- PROC_TGID_SCHEDSTAT,
-#endif
-#ifdef CONFIG_CPUSETS
- PROC_TGID_CPUSET,
-#endif
-#ifdef CONFIG_SECURITY
- PROC_TGID_ATTR,
- PROC_TGID_ATTR_CURRENT,
- PROC_TGID_ATTR_PREV,
- PROC_TGID_ATTR_EXEC,
- PROC_TGID_ATTR_FSCREATE,
- PROC_TGID_ATTR_KEYCREATE,
- PROC_TGID_ATTR_SOCKCREATE,
-#endif
-#ifdef CONFIG_AUDITSYSCALL
- PROC_TGID_LOGINUID,
-#endif
- PROC_TGID_OOM_SCORE,
- PROC_TGID_OOM_ADJUST,
- PROC_TID_INO,
- PROC_TID_STATUS,
- PROC_TID_MEM,
-#ifdef CONFIG_SECCOMP
- PROC_TID_SECCOMP,
-#endif
- PROC_TID_CWD,
- PROC_TID_ROOT,
- PROC_TID_EXE,
- PROC_TID_FD,
- PROC_TID_ENVIRON,
- PROC_TID_AUXV,
- PROC_TID_CMDLINE,
- PROC_TID_STAT,
- PROC_TID_STATM,
- PROC_TID_MAPS,
- PROC_TID_NUMA_MAPS,
- PROC_TID_MOUNTS,
- PROC_TID_MOUNTSTATS,
- PROC_TID_WCHAN,
-#ifdef CONFIG_MMU
- PROC_TID_SMAPS,
-#endif
-#ifdef CONFIG_SCHEDSTATS
- PROC_TID_SCHEDSTAT,
-#endif
-#ifdef CONFIG_CPUSETS
- PROC_TID_CPUSET,
-#endif
-#ifdef CONFIG_SECURITY
- PROC_TID_ATTR,
- PROC_TID_ATTR_CURRENT,
- PROC_TID_ATTR_PREV,
- PROC_TID_ATTR_EXEC,
- PROC_TID_ATTR_FSCREATE,
- PROC_TID_ATTR_KEYCREATE,
- PROC_TID_ATTR_SOCKCREATE,
-#endif
-#ifdef CONFIG_AUDITSYSCALL
- PROC_TID_LOGINUID,
-#endif
- PROC_TID_OOM_SCORE,
- PROC_TID_OOM_ADJUST,
-
- /* Add new entries before this */
- PROC_TID_FD_DIR = 0x8000, /* 0x8000-0xffff */
-};
/* Worst case buffer size needed for holding an integer. */
#define PROC_NUMBUF 10
struct pid_entry {
- int type;
int len;
char *name;
mode_t mode;
union proc_op op;
};
-#define NOD(TYPE, NAME, MODE, IOP, FOP, OP) { \
- .type = (TYPE), \
+#define NOD(NAME, MODE, IOP, FOP, OP) { \
.len = sizeof(NAME) - 1, \
.name = (NAME), \
.mode = MODE, \
.op = OP, \
}
-#define DIR(TYPE, NAME, MODE, OTYPE) \
- NOD(TYPE, NAME, (S_IFDIR|(MODE)), \
+#define DIR(NAME, MODE, OTYPE) \
+ NOD(NAME, (S_IFDIR|(MODE)), \
&proc_##OTYPE##_inode_operations, &proc_##OTYPE##_operations, \
{} )
-#define LNK(TYPE, NAME, OTYPE) \
- NOD(TYPE, NAME, (S_IFLNK|S_IRWXUGO), \
+#define LNK(NAME, OTYPE) \
+ NOD(NAME, (S_IFLNK|S_IRWXUGO), \
&proc_pid_link_inode_operations, NULL, \
{ .proc_get_link = &proc_##OTYPE##_link } )
-#define REG(TYPE, NAME, MODE, OTYPE) \
- NOD(TYPE, NAME, (S_IFREG|(MODE)), NULL, \
+#define REG(NAME, MODE, OTYPE) \
+ NOD(NAME, (S_IFREG|(MODE)), NULL, \
&proc_##OTYPE##_operations, {})
-#define INF(TYPE, NAME, MODE, OTYPE) \
- NOD(TYPE, NAME, (S_IFREG|(MODE)), \
+#define INF(NAME, MODE, OTYPE) \
+ NOD(NAME, (S_IFREG|(MODE)), \
NULL, &proc_info_file_operations, \
{ .proc_read = &proc_##OTYPE } )
}
-static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task, int ino)
+static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task)
{
struct inode * inode;
struct proc_inode *ei;
/* Common stuff */
ei = PROC_I(inode);
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->i_ino = fake_ino(task->pid, ino);
inode->i_op = &proc_def_inode_operations;
/*
* grab the reference to task.
*/
- ei->pid = get_pid(task->pids[PIDTYPE_PID].pid);
+ ei->pid = get_pid(task_pid(task));
if (!ei->pid)
goto out_unlock;
/* Lookups */
+typedef struct dentry *instantiate_t(struct inode *, struct dentry *, struct task_struct *, void *);
+
+static int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+ char *name, int len,
+ instantiate_t instantiate, struct task_struct *task, void *ptr)
+{
+ struct dentry *child, *dir = filp->f_dentry;
+ struct inode *inode;
+ struct qstr qname;
+ ino_t ino = 0;
+ unsigned type = DT_UNKNOWN;
+
+ qname.name = name;
+ qname.len = len;
+ qname.hash = full_name_hash(name, len);
+
+ child = d_lookup(dir, &qname);
+ if (!child) {
+ struct dentry *new;
+ new = d_alloc(dir, &qname);
+ if (new) {
+ child = instantiate(dir->d_inode, new, task, ptr);
+ if (child)
+ dput(new);
+ else
+ child = new;
+ }
+ }
+ if (!child || IS_ERR(child) || !child->d_inode)
+ goto end_instantiate;
+ inode = child->d_inode;
+ if (inode) {
+ ino = inode->i_ino;
+ type = inode->i_mode >> 12;
+ }
+ dput(child);
+end_instantiate:
+ if (!ino)
+ ino = find_inode_number(dir, &qname);
+ if (!ino)
+ ino = 1;
+ 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;
.d_delete = pid_delete_dentry,
};
-/* SMP-safe */
-static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+static struct dentry *proc_fd_instantiate(struct inode *dir,
+ struct dentry *dentry, struct task_struct *task, void *ptr)
{
- struct task_struct *task = get_proc_task(dir);
- unsigned fd = name_to_int(dentry);
- struct dentry *result = ERR_PTR(-ENOENT);
- struct file * file;
- struct files_struct * files;
- struct inode *inode;
- struct proc_inode *ei;
-
- if (!task)
- goto out_no_task;
- if (fd == ~0U)
- goto out;
+ unsigned fd = *(unsigned *)ptr;
+ struct file *file;
+ struct files_struct *files;
+ struct inode *inode;
+ struct proc_inode *ei;
+ struct dentry *error = ERR_PTR(-ENOENT);
- inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_FD_DIR+fd);
+ inode = proc_pid_make_inode(dir->i_sb, task);
if (!inode)
goto out;
ei = PROC_I(inode);
ei->fd = fd;
files = get_files_struct(task);
if (!files)
- goto out_unlock;
+ goto out_iput;
inode->i_mode = S_IFLNK;
/*
spin_lock(&files->file_lock);
file = fcheck_files(files, fd);
if (!file)
- goto out_unlock2;
+ goto out_unlock;
if (file->f_mode & 1)
inode->i_mode |= S_IRUSR | S_IXUSR;
if (file->f_mode & 2)
inode->i_mode |= S_IWUSR | S_IXUSR;
spin_unlock(&files->file_lock);
put_files_struct(files);
+
inode->i_op = &proc_pid_link_inode_operations;
inode->i_size = 64;
ei->op.proc_get_link = proc_fd_link;
d_add(dentry, inode);
/* Close the race of the process dying before we return the dentry */
if (tid_fd_revalidate(dentry, NULL))
- result = NULL;
-out:
- put_task_struct(task);
-out_no_task:
- return result;
+ error = NULL;
-out_unlock2:
+ out:
+ return error;
+out_unlock:
spin_unlock(&files->file_lock);
put_files_struct(files);
-out_unlock:
+out_iput:
iput(inode);
goto out;
}
+/* SMP-safe */
+static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+{
+ 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 = proc_fd_instantiate(dir, dentry, task, &fd);
+out:
+ put_task_struct(task);
+out_no_task:
+ return result;
+}
+
+static int proc_fd_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+ struct task_struct *task, int fd)
+{
+ 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_dentry;
struct task_struct *p = get_proc_task(inode);
unsigned int fd, tid, ino;
int retval;
- char buf[PROC_NUMBUF];
struct files_struct * files;
struct fdtable *fdt;
for (fd = filp->f_pos-2;
fd < fdt->max_fds;
fd++, filp->f_pos++) {
- unsigned int i,j;
if (!fcheck_files(files, fd))
continue;
rcu_read_unlock();
- j = PROC_NUMBUF;
- i = fd;
- do {
- j--;
- buf[j] = '0' + (i % 10);
- i /= 10;
- } while (i);
-
- ino = fake_ino(tid, PROC_TID_FD_DIR + fd);
- if (filldir(dirent, buf+j, PROC_NUMBUF-j, fd+2, ino, DT_LNK) < 0) {
+ if (proc_fd_fill_cache(filp, dirent, filldir, p, fd) < 0) {
rcu_read_lock();
break;
}
.setattr = proc_setattr,
};
+static struct dentry *proc_pident_instantiate(struct inode *dir,
+ struct dentry *dentry, struct task_struct *task, void *ptr)
+{
+ struct pid_entry *p = ptr;
+ struct inode *inode;
+ struct proc_inode *ei;
+ struct dentry *error = ERR_PTR(-EINVAL);
+
+ inode = proc_pid_make_inode(dir->i_sb, task);
+ if (!inode)
+ goto out;
+
+ ei = PROC_I(inode);
+ inode->i_mode = p->mode;
+ if (S_ISDIR(inode->i_mode))
+ inode->i_nlink = 2; /* Use getattr to fix if necessary */
+ if (p->iop)
+ inode->i_op = p->iop;
+ if (p->fop)
+ inode->i_fop = p->fop;
+ ei->op = p->op;
+ dentry->d_op = &pid_dentry_operations;
+ d_add(dentry, inode);
+ /* Close the race of the process dying before we return the dentry */
+ if (pid_revalidate(dentry, NULL))
+ error = NULL;
+out:
+ return error;
+}
+
/* SMP-safe */
static struct dentry *proc_pident_lookup(struct inode *dir,
struct dentry *dentry,
struct dentry *error;
struct task_struct *task = get_proc_task(dir);
struct pid_entry *p;
- struct proc_inode *ei;
error = ERR_PTR(-ENOENT);
inode = NULL;
if (!p->name)
goto out;
- error = ERR_PTR(-EINVAL);
- inode = proc_pid_make_inode(dir->i_sb, task, p->type);
- if (!inode)
- goto out;
-
- ei = PROC_I(inode);
- inode->i_mode = p->mode;
- if (S_ISDIR(inode->i_mode))
- inode->i_nlink = 2; /* Use getattr to fix if necessary */
- if (p->iop)
- inode->i_op = p->iop;
- if (p->fop)
- inode->i_fop = p->fop;
- ei->op = p->op;
- dentry->d_op = &pid_dentry_operations;
- d_add(dentry, inode);
- /* Close the race of the process dying before we return the dentry */
- if (pid_revalidate(dentry, NULL))
- error = NULL;
+ error = proc_pident_instantiate(dir, dentry, task, p);
out:
put_task_struct(task);
out_no_task:
return error;
}
+static int proc_pident_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+ struct task_struct *task, struct pid_entry *p)
+{
+ return proc_fill_cache(filp, dirent, filldir, p->name, p->len,
+ proc_pident_instantiate, task, p);
+}
+
static int proc_pident_readdir(struct file *filp,
void *dirent, filldir_t filldir,
struct pid_entry *ents, unsigned int nents)
ret = -ENOENT;
if (!task)
- goto out;
+ goto out_no_task;
ret = 0;
pid = task->pid;
- put_task_struct(task);
i = filp->f_pos;
switch (i) {
case 0:
}
p = ents + i;
while (p->name) {
- if (filldir(dirent, p->name, p->len, filp->f_pos,
- fake_ino(pid, p->type), p->mode >> 12) < 0)
+ if (proc_pident_fill_cache(filp, dirent, filldir, task, p) < 0)
goto out;
filp->f_pos++;
p++;
ret = 1;
out:
+ put_task_struct(task);
+out_no_task:
return ret;
}
.write = proc_pid_attr_write,
};
-static struct pid_entry tgid_attr_stuff[] = {
- REG(PROC_TGID_ATTR_CURRENT, "current", S_IRUGO|S_IWUGO, pid_attr),
- REG(PROC_TGID_ATTR_PREV, "prev", S_IRUGO, pid_attr),
- REG(PROC_TGID_ATTR_EXEC, "exec", S_IRUGO|S_IWUGO, pid_attr),
- REG(PROC_TGID_ATTR_FSCREATE, "fscreate", S_IRUGO|S_IWUGO, pid_attr),
- REG(PROC_TGID_ATTR_KEYCREATE, "keycreate", S_IRUGO|S_IWUGO, pid_attr),
- REG(PROC_TGID_ATTR_SOCKCREATE, "sockcreate", S_IRUGO|S_IWUGO, pid_attr),
- {}
-};
-static struct pid_entry tid_attr_stuff[] = {
- REG(PROC_TID_ATTR_CURRENT, "current", S_IRUGO|S_IWUGO, pid_attr),
- REG(PROC_TID_ATTR_PREV, "prev", S_IRUGO, pid_attr),
- REG(PROC_TID_ATTR_EXEC, "exec", S_IRUGO|S_IWUGO, pid_attr),
- REG(PROC_TID_ATTR_FSCREATE, "fscreate", S_IRUGO|S_IWUGO, pid_attr),
- REG(PROC_TID_ATTR_KEYCREATE, "keycreate", S_IRUGO|S_IWUGO, pid_attr),
- REG(PROC_TID_ATTR_SOCKCREATE, "sockcreate", S_IRUGO|S_IWUGO, pid_attr),
+static struct pid_entry attr_dir_stuff[] = {
+ REG("current", S_IRUGO|S_IWUGO, pid_attr),
+ REG("prev", S_IRUGO, pid_attr),
+ REG("exec", S_IRUGO|S_IWUGO, pid_attr),
+ REG("fscreate", S_IRUGO|S_IWUGO, pid_attr),
+ REG("keycreate", S_IRUGO|S_IWUGO, pid_attr),
+ REG("sockcreate", S_IRUGO|S_IWUGO, pid_attr),
{}
};
-static int proc_tgid_attr_readdir(struct file * filp,
+static int proc_attr_dir_readdir(struct file * filp,
void * dirent, filldir_t filldir)
{
return proc_pident_readdir(filp,dirent,filldir,
- tgid_attr_stuff,ARRAY_SIZE(tgid_attr_stuff));
+ attr_dir_stuff,ARRAY_SIZE(attr_dir_stuff));
}
-static int proc_tid_attr_readdir(struct file * filp,
- void * dirent, filldir_t filldir)
-{
- return proc_pident_readdir(filp,dirent,filldir,
- tid_attr_stuff,ARRAY_SIZE(tid_attr_stuff));
-}
-
-static struct file_operations proc_tgid_attr_operations = {
+static struct file_operations proc_attr_dir_operations = {
.read = generic_read_dir,
- .readdir = proc_tgid_attr_readdir,
+ .readdir = proc_attr_dir_readdir,
};
-static struct file_operations proc_tid_attr_operations = {
- .read = generic_read_dir,
- .readdir = proc_tid_attr_readdir,
-};
-
-static struct dentry *proc_tgid_attr_lookup(struct inode *dir,
- struct dentry *dentry, struct nameidata *nd)
-{
- return proc_pident_lookup(dir, dentry, tgid_attr_stuff);
-}
-
-static struct dentry *proc_tid_attr_lookup(struct inode *dir,
+static struct dentry *proc_attr_dir_lookup(struct inode *dir,
struct dentry *dentry, struct nameidata *nd)
{
- return proc_pident_lookup(dir, dentry, tid_attr_stuff);
+ return proc_pident_lookup(dir, dentry, attr_dir_stuff);
}
-static struct inode_operations proc_tgid_attr_inode_operations = {
- .lookup = proc_tgid_attr_lookup,
+static struct inode_operations proc_attr_dir_inode_operations = {
+ .lookup = proc_attr_dir_lookup,
.getattr = pid_getattr,
.setattr = proc_setattr,
};
-static struct inode_operations proc_tid_attr_inode_operations = {
- .lookup = proc_tid_attr_lookup,
- .getattr = pid_getattr,
- .setattr = proc_setattr,
-};
#endif
/*
* describe something that is process related.
*/
static struct pid_entry proc_base_stuff[] = {
- NOD(PROC_TGID_INO, "self", S_IFLNK|S_IRWXUGO,
+ NOD("self", S_IFLNK|S_IRWXUGO,
&proc_self_inode_operations, NULL, {}),
{}
};
.d_delete = pid_delete_dentry,
};
-static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
+static struct dentry *proc_base_instantiate(struct inode *dir,
+ struct dentry *dentry, struct task_struct *task, void *ptr)
{
+ struct pid_entry *p = ptr;
struct inode *inode;
- struct dentry *error;
- struct task_struct *task = get_proc_task(dir);
- struct pid_entry *p;
struct proc_inode *ei;
-
- error = ERR_PTR(-ENOENT);
- inode = NULL;
-
- if (!task)
- goto out_no_task;
-
- /* Lookup the directory entry */
- for (p = proc_base_stuff; p->name; p++) {
- if (p->len != dentry->d_name.len)
- continue;
- if (!memcmp(dentry->d_name.name, p->name, p->len))
- break;
- }
- if (!p->name)
- goto out;
+ struct dentry *error = ERR_PTR(-EINVAL);
/* Allocate the inode */
error = ERR_PTR(-ENOMEM);
/* Initialize the inode */
ei = PROC_I(inode);
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->i_ino = fake_ino(0, p->type);
/*
* grab the reference to the task.
d_add(dentry, inode);
error = NULL;
out:
- put_task_struct(task);
-out_no_task:
return error;
out_iput:
iput(inode);
goto out;
}
+static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
+{
+ struct dentry *error;
+ struct task_struct *task = get_proc_task(dir);
+ struct pid_entry *p;
+
+ error = ERR_PTR(-ENOENT);
+
+ if (!task)
+ goto out_no_task;
+
+ /* Lookup the directory entry */
+ for (p = proc_base_stuff; p->name; p++) {
+ if (p->len != dentry->d_name.len)
+ continue;
+ if (!memcmp(dentry->d_name.name, p->name, p->len))
+ break;
+ }
+ if (!p->name)
+ goto out;
+
+ error = proc_base_instantiate(dir, dentry, task, p);
+
+out:
+ put_task_struct(task);
+out_no_task:
+ return error;
+}
+
+static int proc_base_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+ struct task_struct *task, struct pid_entry *p)
+{
+ return proc_fill_cache(filp, dirent, filldir, p->name, p->len,
+ proc_base_instantiate, task, p);
+}
+
/*
* Thread groups
*/
static struct inode_operations proc_task_inode_operations;
static struct pid_entry tgid_base_stuff[] = {
- DIR(PROC_TGID_TASK, "task", S_IRUGO|S_IXUGO, task),
- DIR(PROC_TGID_FD, "fd", S_IRUSR|S_IXUSR, fd),
- INF(PROC_TGID_ENVIRON, "environ", S_IRUSR, pid_environ),
- INF(PROC_TGID_AUXV, "auxv", S_IRUSR, pid_auxv),
- INF(PROC_TGID_STATUS, "status", S_IRUGO, pid_status),
- INF(PROC_TGID_CMDLINE, "cmdline", S_IRUGO, pid_cmdline),
- INF(PROC_TGID_STAT, "stat", S_IRUGO, tgid_stat),
- INF(PROC_TGID_STATM, "statm", S_IRUGO, pid_statm),
- REG(PROC_TGID_MAPS, "maps", S_IRUGO, maps),
+ DIR("task", S_IRUGO|S_IXUGO, task),
+ DIR("fd", S_IRUSR|S_IXUSR, fd),
+ INF("environ", S_IRUSR, pid_environ),
+ INF("auxv", S_IRUSR, pid_auxv),
+ INF("status", S_IRUGO, pid_status),
+ INF("cmdline", S_IRUGO, pid_cmdline),
+ INF("stat", S_IRUGO, tgid_stat),
+ INF("statm", S_IRUGO, pid_statm),
+ REG("maps", S_IRUGO, maps),
#ifdef CONFIG_NUMA
- REG(PROC_TGID_NUMA_MAPS, "numa_maps", S_IRUGO, numa_maps),
+ REG("numa_maps", S_IRUGO, numa_maps),
#endif
- REG(PROC_TGID_MEM, "mem", S_IRUSR|S_IWUSR, mem),
+ REG("mem", S_IRUSR|S_IWUSR, mem),
#ifdef CONFIG_SECCOMP
- REG(PROC_TGID_SECCOMP, "seccomp", S_IRUSR|S_IWUSR, seccomp),
+ REG("seccomp", S_IRUSR|S_IWUSR, seccomp),
#endif
- LNK(PROC_TGID_CWD, "cwd", cwd),
- LNK(PROC_TGID_ROOT, "root", root),
- LNK(PROC_TGID_EXE, "exe", exe),
- REG(PROC_TGID_MOUNTS, "mounts", S_IRUGO, mounts),
- REG(PROC_TGID_MOUNTSTATS, "mountstats", S_IRUSR, mountstats),
+ LNK("cwd", cwd),
+ LNK("root", root),
+ LNK("exe", exe),
+ REG("mounts", S_IRUGO, mounts),
+ REG("mountstats", S_IRUSR, mountstats),
#ifdef CONFIG_MMU
- REG(PROC_TGID_SMAPS, "smaps", S_IRUGO, smaps),
+ REG("smaps", S_IRUGO, smaps),
#endif
#ifdef CONFIG_SECURITY
- DIR(PROC_TGID_ATTR, "attr", S_IRUGO|S_IXUGO, tgid_attr),
+ DIR("attr", S_IRUGO|S_IXUGO, attr_dir),
#endif
#ifdef CONFIG_KALLSYMS
- INF(PROC_TGID_WCHAN, "wchan", S_IRUGO, pid_wchan),
+ INF("wchan", S_IRUGO, pid_wchan),
#endif
#ifdef CONFIG_SCHEDSTATS
- INF(PROC_TGID_SCHEDSTAT, "schedstat", S_IRUGO, pid_schedstat),
+ INF("schedstat", S_IRUGO, pid_schedstat),
#endif
#ifdef CONFIG_CPUSETS
- REG(PROC_TGID_CPUSET, "cpuset", S_IRUGO, cpuset),
+ REG("cpuset", S_IRUGO, cpuset),
#endif
- INF(PROC_TGID_OOM_SCORE, "oom_score", S_IRUGO, oom_score),
- REG(PROC_TGID_OOM_ADJUST, "oom_adj", S_IRUGO|S_IWUSR, oom_adjust),
+ INF("oom_score", S_IRUGO, oom_score),
+ REG("oom_adj", S_IRUGO|S_IWUSR, oom_adjust),
#ifdef CONFIG_AUDITSYSCALL
- REG(PROC_TGID_LOGINUID, "loginuid", S_IWUSR|S_IRUGO, loginuid),
+ REG("loginuid", S_IWUSR|S_IRUGO, loginuid),
#endif
{}
};
return;
}
+struct dentry *proc_pid_instantiate(struct inode *dir,
+ struct dentry * dentry, struct task_struct *task, void *ptr)
+{
+ struct dentry *error = ERR_PTR(-ENOENT);
+ struct inode *inode;
+
+ inode = proc_pid_make_inode(dir->i_sb, task);
+ if (!inode)
+ goto out;
+
+ inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
+ inode->i_op = &proc_tgid_base_inode_operations;
+ inode->i_fop = &proc_tgid_base_operations;
+ inode->i_flags|=S_IMMUTABLE;
+ inode->i_nlink = 4;
+#ifdef CONFIG_SECURITY
+ inode->i_nlink += 1;
+#endif
+
+ dentry->d_op = &pid_dentry_operations;
+
+ d_add(dentry, inode);
+ /* Close the race of the process dying before we return the dentry */
+ if (pid_revalidate(dentry, NULL))
+ error = NULL;
+out:
+ return error;
+}
+
/* SMP-safe */
struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
{
struct dentry *result = ERR_PTR(-ENOENT);
struct task_struct *task;
- struct inode *inode;
unsigned tgid;
result = proc_base_lookup(dir, dentry);
if (!task)
goto out;
- inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO);
- if (!inode)
- goto out_put_task;
-
- inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
- inode->i_op = &proc_tgid_base_inode_operations;
- inode->i_fop = &proc_tgid_base_operations;
- inode->i_flags|=S_IMMUTABLE;
-#ifdef CONFIG_SECURITY
- inode->i_nlink = 5;
-#else
- inode->i_nlink = 4;
-#endif
-
- dentry->d_op = &pid_dentry_operations;
-
- d_add(dentry, inode);
- /* Close the race of the process dying before we return the dentry */
- if (pid_revalidate(dentry, NULL))
- result = NULL;
-
-out_put_task:
+ result = proc_pid_instantiate(dir, dentry, task, NULL);
put_task_struct(task);
out:
return result;
#define TGID_OFFSET (FIRST_PROCESS_ENTRY + (1 /* /proc/self */))
+static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+ struct task_struct *task, int tgid)
+{
+ char name[PROC_NUMBUF];
+ int len = snprintf(name, sizeof(name), "%d", tgid);
+ return proc_fill_cache(filp, dirent, filldir, name, len,
+ proc_pid_instantiate, task, NULL);
+}
+
/* for the /proc/ directory itself, after non-process stuff has been done */
int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
- char buf[PROC_NUMBUF];
unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY;
+ struct task_struct *reaper = get_proc_task(filp->f_dentry->d_inode);
struct task_struct *task;
int tgid;
+ if (!reaper)
+ goto out_no_task;
+
for (; nr < (ARRAY_SIZE(proc_base_stuff) - 1); filp->f_pos++, nr++) {
struct pid_entry *p = &proc_base_stuff[nr];
- if (filldir(dirent, p->name, p->len, filp->f_pos,
- fake_ino(0, p->type), p->mode >> 12) < 0)
+ if (proc_base_fill_cache(filp, dirent, filldir, reaper, p) < 0)
goto out;
}
for (task = next_tgid(tgid);
task;
put_task_struct(task), task = next_tgid(tgid + 1)) {
- int len;
- ino_t ino;
tgid = task->pid;
filp->f_pos = tgid + TGID_OFFSET;
- len = snprintf(buf, sizeof(buf), "%d", tgid);
- ino = fake_ino(tgid, PROC_TGID_INO);
- if (filldir(dirent, buf, len, filp->f_pos, ino, DT_DIR) < 0) {
+ if (proc_pid_fill_cache(filp, dirent, filldir, task, tgid) < 0) {
put_task_struct(task);
goto out;
}
}
filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET;
out:
+ put_task_struct(reaper);
+out_no_task:
return 0;
}
* Tasks
*/
static struct pid_entry tid_base_stuff[] = {
- DIR(PROC_TID_FD, "fd", S_IRUSR|S_IXUSR, fd),
- INF(PROC_TID_ENVIRON, "environ", S_IRUSR, pid_environ),
- INF(PROC_TID_AUXV, "auxv", S_IRUSR, pid_auxv),
- INF(PROC_TID_STATUS, "status", S_IRUGO, pid_status),
- INF(PROC_TID_CMDLINE, "cmdline", S_IRUGO, pid_cmdline),
- INF(PROC_TID_STAT, "stat", S_IRUGO, tid_stat),
- INF(PROC_TID_STATM, "statm", S_IRUGO, pid_statm),
- REG(PROC_TID_MAPS, "maps", S_IRUGO, maps),
+ DIR("fd", S_IRUSR|S_IXUSR, fd),
+ INF("environ", S_IRUSR, pid_environ),
+ INF("auxv", S_IRUSR, pid_auxv),
+ INF("status", S_IRUGO, pid_status),
+ INF("cmdline", S_IRUGO, pid_cmdline),
+ INF("stat", S_IRUGO, tid_stat),
+ INF("statm", S_IRUGO, pid_statm),
+ REG("maps", S_IRUGO, maps),
#ifdef CONFIG_NUMA
- REG(PROC_TID_NUMA_MAPS, "numa_maps", S_IRUGO, numa_maps),
+ REG("numa_maps", S_IRUGO, numa_maps),
#endif
- REG(PROC_TID_MEM, "mem", S_IRUSR|S_IWUSR, mem),
+ REG("mem", S_IRUSR|S_IWUSR, mem),
#ifdef CONFIG_SECCOMP
- REG(PROC_TID_SECCOMP, "seccomp", S_IRUSR|S_IWUSR, seccomp),
+ REG("seccomp", S_IRUSR|S_IWUSR, seccomp),
#endif
- LNK(PROC_TID_CWD, "cwd", cwd),
- LNK(PROC_TID_ROOT, "root", root),
- LNK(PROC_TID_EXE, "exe", exe),
- REG(PROC_TID_MOUNTS, "mounts", S_IRUGO, mounts),
+ LNK("cwd", cwd),
+ LNK("root", root),
+ LNK("exe", exe),
+ REG("mounts", S_IRUGO, mounts),
#ifdef CONFIG_MMU
- REG(PROC_TID_SMAPS, "smaps", S_IRUGO, smaps),
+ REG("smaps", S_IRUGO, smaps),
#endif
#ifdef CONFIG_SECURITY
- DIR(PROC_TID_ATTR, "attr", S_IRUGO|S_IXUGO, tid_attr),
+ DIR("attr", S_IRUGO|S_IXUGO, attr_dir),
#endif
#ifdef CONFIG_KALLSYMS
- INF(PROC_TID_WCHAN, "wchan", S_IRUGO, pid_wchan),
+ INF("wchan", S_IRUGO, pid_wchan),
#endif
#ifdef CONFIG_SCHEDSTATS
- INF(PROC_TID_SCHEDSTAT, "schedstat", S_IRUGO, pid_schedstat),
+ INF("schedstat", S_IRUGO, pid_schedstat),
#endif
#ifdef CONFIG_CPUSETS
- REG(PROC_TID_CPUSET, "cpuset", S_IRUGO, cpuset),
+ REG("cpuset", S_IRUGO, cpuset),
#endif
- INF(PROC_TID_OOM_SCORE, "oom_score", S_IRUGO, oom_score),
- REG(PROC_TID_OOM_ADJUST, "oom_adj", S_IRUGO|S_IWUSR, oom_adjust),
+ INF("oom_score", S_IRUGO, oom_score),
+ REG("oom_adj", S_IRUGO|S_IWUSR, oom_adjust),
#ifdef CONFIG_AUDITSYSCALL
- REG(PROC_TID_LOGINUID, "loginuid", S_IWUSR|S_IRUGO, loginuid),
+ REG("loginuid", S_IWUSR|S_IRUGO, loginuid),
#endif
{}
};
.setattr = proc_setattr,
};
+static struct dentry *proc_task_instantiate(struct inode *dir,
+ struct dentry *dentry, struct task_struct *task, void *ptr)
+{
+ struct dentry *error = ERR_PTR(-ENOENT);
+ struct inode *inode;
+ inode = proc_pid_make_inode(dir->i_sb, task);
+
+ if (!inode)
+ goto out;
+ inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
+ inode->i_op = &proc_tid_base_inode_operations;
+ inode->i_fop = &proc_tid_base_operations;
+ inode->i_flags|=S_IMMUTABLE;
+ inode->i_nlink = 3;
+#ifdef CONFIG_SECURITY
+ inode->i_nlink += 1;
+#endif
+
+ dentry->d_op = &pid_dentry_operations;
+
+ d_add(dentry, inode);
+ /* Close the race of the process dying before we return the dentry */
+ if (pid_revalidate(dentry, NULL))
+ error = NULL;
+out:
+ return error;
+}
+
/* SMP-safe */
static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
{
struct dentry *result = ERR_PTR(-ENOENT);
struct task_struct *task;
struct task_struct *leader = get_proc_task(dir);
- struct inode *inode;
unsigned tid;
if (!leader)
if (leader->tgid != task->tgid)
goto out_drop_task;
- inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_INO);
-
-
- if (!inode)
- goto out_drop_task;
- inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
- inode->i_op = &proc_tid_base_inode_operations;
- inode->i_fop = &proc_tid_base_operations;
- inode->i_flags|=S_IMMUTABLE;
-#ifdef CONFIG_SECURITY
- inode->i_nlink = 4;
-#else
- inode->i_nlink = 3;
-#endif
-
- dentry->d_op = &pid_dentry_operations;
-
- d_add(dentry, inode);
- /* Close the race of the process dying before we return the dentry */
- if (pid_revalidate(dentry, NULL))
- result = NULL;
-
+ result = proc_task_instantiate(dir, dentry, task, NULL);
out_drop_task:
put_task_struct(task);
out:
return pos;
}
+static int proc_task_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+ struct task_struct *task, int tid)
+{
+ char name[PROC_NUMBUF];
+ int len = snprintf(name, sizeof(name), "%d", tid);
+ return proc_fill_cache(filp, dirent, filldir, name, len,
+ proc_task_instantiate, task, NULL);
+}
+
/* for the /proc/TGID/task/ directories */
static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
- char buf[PROC_NUMBUF];
struct dentry *dentry = filp->f_dentry;
struct inode *inode = dentry->d_inode;
struct task_struct *leader = get_proc_task(inode);
for (task = first_tid(leader, tid, pos - 2);
task;
task = next_tid(task), pos++) {
- int len;
tid = task->pid;
- len = snprintf(buf, sizeof(buf), "%d", tid);
- ino = fake_ino(tid, PROC_TID_INO);
- if (filldir(dirent, buf, len, pos, ino, DT_DIR < 0)) {
+ if (proc_task_fill_cache(filp, dirent, filldir, task, tid) < 0) {
/* returning this tgid failed, save it as the first
* pid for the next readir call */
filp->f_version = tid;