#include <linux/string.h>
#include <linux/seq_file.h>
#include <linux/namei.h>
-#include <linux/namespace.h>
+#include <linux/mnt_namespace.h>
#include <linux/mm.h>
#include <linux/smp_lock.h>
#include <linux/rcupdate.h>
#include <linux/audit.h>
#include <linux/poll.h>
#include <linux/nsproxy.h>
+#include <linux/oom.h>
#include "internal.h"
/* NOTE:
* 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
+#define PROC_NUMBUF 13
struct pid_entry {
- int type;
int len;
char *name;
mode_t mode;
- struct inode_operations *iop;
- struct file_operations *fop;
+ const struct inode_operations *iop;
+ const struct file_operations *fop;
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 } )
return error;
}
-static struct inode_operations proc_def_inode_operations = {
+static const struct inode_operations proc_def_inode_operations = {
.setattr = proc_setattr,
};
static int mounts_open(struct inode *inode, struct file *file)
{
struct task_struct *task = get_proc_task(inode);
- struct namespace *namespace = NULL;
+ struct mnt_namespace *ns = NULL;
struct proc_mounts *p;
int ret = -EINVAL;
if (task) {
task_lock(task);
- namespace = task->nsproxy->namespace;
- if (namespace)
- get_namespace(namespace);
+ if (task->nsproxy) {
+ ns = task->nsproxy->mnt_ns;
+ if (ns)
+ get_mnt_ns(ns);
+ }
task_unlock(task);
put_task_struct(task);
}
- if (namespace) {
+ if (ns) {
ret = -ENOMEM;
p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
if (p) {
file->private_data = &p->m;
ret = seq_open(file, &mounts_op);
if (!ret) {
- p->m.private = namespace;
- p->event = namespace->event;
+ p->m.private = ns;
+ p->event = ns->event;
return 0;
}
kfree(p);
}
- put_namespace(namespace);
+ put_mnt_ns(ns);
}
return ret;
}
static int mounts_release(struct inode *inode, struct file *file)
{
struct seq_file *m = file->private_data;
- struct namespace *namespace = m->private;
- put_namespace(namespace);
+ struct mnt_namespace *ns = m->private;
+ put_mnt_ns(ns);
return seq_release(inode, file);
}
static unsigned mounts_poll(struct file *file, poll_table *wait)
{
struct proc_mounts *p = file->private_data;
- struct namespace *ns = p->m.private;
+ struct mnt_namespace *ns = p->m.private;
unsigned res = 0;
poll_wait(file, &ns->poll, wait);
return res;
}
-static struct file_operations proc_mounts_operations = {
+static const struct file_operations proc_mounts_operations = {
.open = mounts_open,
.read = seq_read,
.llseek = seq_lseek,
if (!ret) {
struct seq_file *m = file->private_data;
- struct namespace *namespace = NULL;
+ struct mnt_namespace *mnt_ns = NULL;
struct task_struct *task = get_proc_task(inode);
if (task) {
task_lock(task);
- namespace = task->nsproxy->namespace;
- if (namespace)
- get_namespace(namespace);
+ if (task->nsproxy)
+ mnt_ns = task->nsproxy->mnt_ns;
+ if (mnt_ns)
+ get_mnt_ns(mnt_ns);
task_unlock(task);
put_task_struct(task);
}
- if (namespace)
- m->private = namespace;
+ if (mnt_ns)
+ m->private = mnt_ns;
else {
seq_release(inode, file);
ret = -EINVAL;
return ret;
}
-static struct file_operations proc_mountstats_operations = {
+static const struct file_operations proc_mountstats_operations = {
.open = mountstats_open,
.read = seq_read,
.llseek = seq_lseek,
static ssize_t proc_info_read(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
unsigned long page;
ssize_t length;
struct task_struct *task = get_proc_task(inode);
return length;
}
-static struct file_operations proc_info_file_operations = {
+static const struct file_operations proc_info_file_operations = {
.read = proc_info_read,
};
static ssize_t mem_read(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
- struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+ struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
char *page;
unsigned long src = *ppos;
int ret = -ESRCH;
#ifndef mem_write
/* This is a security hazard */
-static ssize_t mem_write(struct file * file, const char * buf,
+static ssize_t mem_write(struct file * file, const char __user *buf,
size_t count, loff_t *ppos)
{
int copied;
char *page;
- struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+ struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
unsigned long dst = *ppos;
copied = -ESRCH;
return file->f_pos;
}
-static struct file_operations proc_mem_operations = {
+static const struct file_operations proc_mem_operations = {
.llseek = mem_lseek,
.read = mem_read,
.write = mem_write,
static ssize_t oom_adjust_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+ struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
char buffer[PROC_NUMBUF];
size_t len;
int oom_adjust;
char buffer[PROC_NUMBUF], *end;
int oom_adjust;
- if (!capable(CAP_SYS_RESOURCE))
- return -EPERM;
memset(buffer, 0, sizeof(buffer));
if (count > sizeof(buffer) - 1)
count = sizeof(buffer) - 1;
if (copy_from_user(buffer, buf, count))
return -EFAULT;
oom_adjust = simple_strtol(buffer, &end, 0);
- if ((oom_adjust < -16 || oom_adjust > 15) && oom_adjust != OOM_DISABLE)
+ if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) &&
+ oom_adjust != OOM_DISABLE)
return -EINVAL;
if (*end == '\n')
end++;
- task = get_proc_task(file->f_dentry->d_inode);
+ task = get_proc_task(file->f_path.dentry->d_inode);
if (!task)
return -ESRCH;
+ if (oom_adjust < task->oomkilladj && !capable(CAP_SYS_RESOURCE)) {
+ put_task_struct(task);
+ return -EACCES;
+ }
task->oomkilladj = oom_adjust;
put_task_struct(task);
if (end - buffer == 0)
return end - buffer;
}
-static struct file_operations proc_oom_adjust_operations = {
+static const struct file_operations proc_oom_adjust_operations = {
.read = oom_adjust_read,
.write = oom_adjust_write,
};
+static ssize_t clear_refs_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct task_struct *task;
+ char buffer[PROC_NUMBUF], *end;
+ struct mm_struct *mm;
+
+ memset(buffer, 0, sizeof(buffer));
+ if (count > sizeof(buffer) - 1)
+ count = sizeof(buffer) - 1;
+ if (copy_from_user(buffer, buf, count))
+ return -EFAULT;
+ if (!simple_strtol(buffer, &end, 0))
+ return -EINVAL;
+ if (*end == '\n')
+ end++;
+ task = get_proc_task(file->f_path.dentry->d_inode);
+ if (!task)
+ return -ESRCH;
+ mm = get_task_mm(task);
+ if (mm) {
+ clear_refs_smap(mm);
+ mmput(mm);
+ }
+ put_task_struct(task);
+ if (end - buffer == 0)
+ return -EIO;
+ return end - buffer;
+}
+
+static struct file_operations proc_clear_refs_operations = {
+ .write = clear_refs_write,
+};
+
#ifdef CONFIG_AUDITSYSCALL
#define TMPBUFLEN 21
static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
struct task_struct *task = get_proc_task(inode);
ssize_t length;
char tmpbuf[TMPBUFLEN];
static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
char *page, *tmp;
ssize_t length;
uid_t loginuid;
return length;
}
-static struct file_operations proc_loginuid_operations = {
+static const struct file_operations proc_loginuid_operations = {
.read = proc_loginuid_read,
.write = proc_loginuid_write,
};
return result;
}
-static struct file_operations proc_seccomp_operations = {
+static const struct file_operations proc_seccomp_operations = {
.read = seccomp_read,
.write = seccomp_write,
};
#endif /* CONFIG_SECCOMP */
+#ifdef CONFIG_FAULT_INJECTION
+static ssize_t proc_fault_inject_read(struct file * file, char __user * buf,
+ size_t count, loff_t *ppos)
+{
+ struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+ char buffer[PROC_NUMBUF];
+ size_t len;
+ int make_it_fail;
+ loff_t __ppos = *ppos;
+
+ if (!task)
+ return -ESRCH;
+ make_it_fail = task->make_it_fail;
+ put_task_struct(task);
+
+ len = snprintf(buffer, sizeof(buffer), "%i\n", make_it_fail);
+ if (__ppos >= len)
+ return 0;
+ if (count > len-__ppos)
+ count = len-__ppos;
+ if (copy_to_user(buf, buffer + __ppos, count))
+ return -EFAULT;
+ *ppos = __ppos + count;
+ return count;
+}
+
+static ssize_t proc_fault_inject_write(struct file * file,
+ const char __user * buf, size_t count, loff_t *ppos)
+{
+ struct task_struct *task;
+ char buffer[PROC_NUMBUF], *end;
+ int make_it_fail;
+
+ if (!capable(CAP_SYS_RESOURCE))
+ return -EPERM;
+ memset(buffer, 0, sizeof(buffer));
+ if (count > sizeof(buffer) - 1)
+ count = sizeof(buffer) - 1;
+ if (copy_from_user(buffer, buf, count))
+ return -EFAULT;
+ make_it_fail = simple_strtol(buffer, &end, 0);
+ if (*end == '\n')
+ end++;
+ task = get_proc_task(file->f_dentry->d_inode);
+ if (!task)
+ return -ESRCH;
+ task->make_it_fail = make_it_fail;
+ put_task_struct(task);
+ if (end - buffer == 0)
+ return -EIO;
+ return end - buffer;
+}
+
+static const struct file_operations proc_fault_inject_operations = {
+ .read = proc_fault_inject_read,
+ .write = proc_fault_inject_write,
+};
+#endif
+
static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct inode *inode = dentry->d_inode;
return error;
}
-static struct inode_operations proc_pid_link_inode_operations = {
+static const struct inode_operations proc_pid_link_inode_operations = {
.readlink = proc_pid_readlink,
.follow_link = proc_pid_follow_link,
.setattr = proc_setattr,
}
-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_task_pid(task, PIDTYPE_PID);
if (!ei->pid)
goto out_unlock;
/* Lookups */
+typedef struct dentry *instantiate_t(struct inode *, struct dentry *, struct task_struct *, void *);
+
+/*
+ * Fill a directory entry.
+ *
+ * If possible create the dcache entry and derive our inode number and
+ * file type from dcache entry.
+ *
+ * Since all of the proc inode numbers are dynamically generated, the inode
+ * numbers do not exist until the inode is cache. This means creating the
+ * the dcache entry in readdir is necessary to keep the inode numbers
+ * reported by readdir in sync with the inode numbers reported
+ * by stat.
+ */
+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_path.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;
spin_lock(&files->file_lock);
file = fcheck_files(files, fd);
if (file) {
- *mnt = mntget(file->f_vfsmnt);
- *dentry = dget(file->f_dentry);
+ *mnt = mntget(file->f_path.mnt);
+ *dentry = dget(file->f_path.dentry);
spin_unlock(&files->file_lock);
put_files_struct(files);
return 0;
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);
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);
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 dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
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;
}
return retval;
}
-static struct file_operations proc_fd_operations = {
+static const struct file_operations proc_fd_operations = {
.read = generic_read_dir,
.readdir = proc_readfd,
};
/*
+ * /proc/pid/fd needs a special permission handler so that a process can still
+ * access /proc/self/fd after it has executed a setuid().
+ */
+static int proc_fd_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ int rv;
+
+ rv = generic_permission(inode, mask, NULL);
+ if (rv == 0)
+ return 0;
+ if (task_pid(current) == proc_pid(inode))
+ rv = 0;
+ return rv;
+}
+
+/*
* proc directories can do almost nothing..
*/
-static struct inode_operations proc_fd_inode_operations = {
+static const struct inode_operations proc_fd_inode_operations = {
.lookup = proc_lookupfd,
+ .permission = proc_fd_permission,
.setattr = proc_setattr,
};
struct proc_inode *ei;
struct dentry *error = ERR_PTR(-EINVAL);
- inode = proc_pid_make_inode(dir->i_sb, task, p->type);
+ inode = proc_pid_make_inode(dir->i_sb, task);
if (!inode)
goto out;
return error;
}
-/* SMP-safe */
static struct dentry *proc_pident_lookup(struct inode *dir,
struct dentry *dentry,
- struct pid_entry *ents)
+ struct pid_entry *ents,
+ unsigned int nents)
{
struct inode *inode;
struct dentry *error;
struct task_struct *task = get_proc_task(dir);
- struct pid_entry *p;
+ struct pid_entry *p, *last;
error = ERR_PTR(-ENOENT);
inode = NULL;
* Yes, it does not scale. And it should not. Don't add
* new entries into /proc/<tgid>/ without very good reasons.
*/
- for (p = ents; p->name; p++) {
+ last = &ents[nents - 1];
+ for (p = ents; p <= last; p++) {
if (p->len != dentry->d_name.len)
continue;
if (!memcmp(dentry->d_name.name, p->name, p->len))
break;
}
- if (!p->name)
+ if (p > last)
goto out;
error = proc_pident_instantiate(dir, dentry, task, p);
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)
{
int i;
int pid;
- struct dentry *dentry = filp->f_dentry;
+ struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct task_struct *task = get_proc_task(inode);
- struct pid_entry *p;
+ struct pid_entry *p, *last;
ino_t ino;
int ret;
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:
goto out;
}
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)
+ last = &ents[nents - 1];
+ while (p <= last) {
+ 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;
}
static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
- unsigned long page;
+ struct inode * inode = file->f_path.dentry->d_inode;
+ char *p = NULL;
ssize_t length;
struct task_struct *task = get_proc_task(inode);
- length = -ESRCH;
if (!task)
- goto out_no_task;
-
- if (count > PAGE_SIZE)
- count = PAGE_SIZE;
- length = -ENOMEM;
- if (!(page = __get_free_page(GFP_KERNEL)))
- goto out;
+ return -ESRCH;
length = security_getprocattr(task,
- (char*)file->f_dentry->d_name.name,
- (void*)page, count);
- if (length >= 0)
- length = simple_read_from_buffer(buf, count, ppos, (char *)page, length);
- free_page(page);
-out:
+ (char*)file->f_path.dentry->d_name.name,
+ &p);
put_task_struct(task);
-out_no_task:
+ if (length > 0)
+ length = simple_read_from_buffer(buf, count, ppos, p, length);
+ kfree(p);
return length;
}
static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
- struct inode * inode = file->f_dentry->d_inode;
+ struct inode * inode = file->f_path.dentry->d_inode;
char *page;
ssize_t length;
struct task_struct *task = get_proc_task(inode);
goto out_free;
length = security_setprocattr(task,
- (char*)file->f_dentry->d_name.name,
+ (char*)file->f_path.dentry->d_name.name,
(void*)page, count);
out_free:
free_page((unsigned long) page);
return length;
}
-static struct file_operations proc_pid_attr_operations = {
+static const struct file_operations proc_pid_attr_operations = {
.read = proc_pid_attr_read,
.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 = {
- .read = generic_read_dir,
- .readdir = proc_tgid_attr_readdir,
-};
-
-static struct file_operations proc_tid_attr_operations = {
+static const struct file_operations proc_attr_dir_operations = {
.read = generic_read_dir,
- .readdir = proc_tid_attr_readdir,
+ .readdir = proc_attr_dir_readdir,
};
-static struct dentry *proc_tgid_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, tgid_attr_stuff);
+ return proc_pident_lookup(dir, dentry,
+ attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff));
}
-static struct dentry *proc_tid_attr_lookup(struct inode *dir,
- struct dentry *dentry, struct nameidata *nd)
-{
- return proc_pident_lookup(dir, dentry, tid_attr_stuff);
-}
-
-static struct inode_operations proc_tgid_attr_inode_operations = {
- .lookup = proc_tgid_attr_lookup,
+static const 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
/*
return ERR_PTR(vfs_follow_link(nd,tmp));
}
-static struct inode_operations proc_self_inode_operations = {
+static const struct inode_operations proc_self_inode_operations = {
.readlink = proc_self_readlink,
.follow_link = proc_self_follow_link,
};
* 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, {}),
- {}
};
/*
/* 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.
*/
- ei->pid = get_pid(task_pid(task));
+ ei->pid = get_task_pid(task, PIDTYPE_PID);
if (!ei->pid)
goto out_iput;
{
struct dentry *error;
struct task_struct *task = get_proc_task(dir);
- struct pid_entry *p;
+ struct pid_entry *p, *last;
error = ERR_PTR(-ENOENT);
goto out_no_task;
/* Lookup the directory entry */
- for (p = proc_base_stuff; p->name; p++) {
+ last = &proc_base_stuff[ARRAY_SIZE(proc_base_stuff) - 1];
+ for (p = proc_base_stuff; p <= last; p++) {
if (p->len != dentry->d_name.len)
continue;
if (!memcmp(dentry->d_name.name, p->name, p->len))
break;
}
- if (!p->name)
+ if (p > last)
goto out;
error = proc_base_instantiate(dir, dentry, task, p);
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);
+}
+
+#ifdef CONFIG_TASK_IO_ACCOUNTING
+static int proc_pid_io_accounting(struct task_struct *task, char *buffer)
+{
+ return sprintf(buffer,
+#ifdef CONFIG_TASK_XACCT
+ "rchar: %llu\n"
+ "wchar: %llu\n"
+ "syscr: %llu\n"
+ "syscw: %llu\n"
+#endif
+ "read_bytes: %llu\n"
+ "write_bytes: %llu\n"
+ "cancelled_write_bytes: %llu\n",
+#ifdef CONFIG_TASK_XACCT
+ (unsigned long long)task->rchar,
+ (unsigned long long)task->wchar,
+ (unsigned long long)task->syscr,
+ (unsigned long long)task->syscw,
+#endif
+ (unsigned long long)task->ioac.read_bytes,
+ (unsigned long long)task->ioac.write_bytes,
+ (unsigned long long)task->ioac.cancelled_write_bytes);
+}
+#endif
+
/*
* Thread groups
*/
-static struct file_operations proc_task_operations;
-static struct inode_operations proc_task_inode_operations;
+static const struct file_operations proc_task_operations;
+static const 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("clear_refs", S_IWUSR, clear_refs),
+ 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
+#ifdef CONFIG_FAULT_INJECTION
+ REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject),
+#endif
+#ifdef CONFIG_TASK_IO_ACCOUNTING
+ INF("io", S_IRUGO, pid_io_accounting),
#endif
- {}
};
static int proc_tgid_base_readdir(struct file * filp,
tgid_base_stuff,ARRAY_SIZE(tgid_base_stuff));
}
-static struct file_operations proc_tgid_base_operations = {
+static const struct file_operations proc_tgid_base_operations = {
.read = generic_read_dir,
.readdir = proc_tgid_base_readdir,
};
static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
- return proc_pident_lookup(dir, dentry, tgid_base_stuff);
+ return proc_pident_lookup(dir, dentry,
+ tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff));
}
-static struct inode_operations proc_tgid_base_inode_operations = {
+static const struct inode_operations proc_tgid_base_inode_operations = {
.lookup = proc_tgid_base_lookup,
.getattr = pid_getattr,
.setattr = proc_setattr,
return;
}
-struct dentry *proc_pid_instantiate(struct inode *dir,
- struct dentry * dentry, struct task_struct *task, void *ptr)
+static 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, PROC_TGID_INO);
+ inode = proc_pid_make_inode(dir->i_sb, task);
if (!inode)
goto 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);
return task;
}
-#define TGID_OFFSET (FIRST_PROCESS_ENTRY + (1 /* /proc/self */))
+#define TGID_OFFSET (FIRST_PROCESS_ENTRY + ARRAY_SIZE(proc_base_stuff))
+
+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_path.dentry->d_inode);
struct task_struct *task;
int tgid;
- for (; nr < (ARRAY_SIZE(proc_base_stuff) - 1); filp->f_pos++, nr++) {
+ if (!reaper)
+ goto out_no_task;
+
+ for (; nr < ARRAY_SIZE(proc_base_stuff); 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("clear_refs", S_IWUSR, clear_refs),
+ 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
+#ifdef CONFIG_FAULT_INJECTION
+ REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject),
#endif
- {}
};
static int proc_tid_base_readdir(struct file * filp,
}
static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
- return proc_pident_lookup(dir, dentry, tid_base_stuff);
+ return proc_pident_lookup(dir, dentry,
+ tid_base_stuff, ARRAY_SIZE(tid_base_stuff));
}
-static struct file_operations proc_tid_base_operations = {
+static const struct file_operations proc_tid_base_operations = {
.read = generic_read_dir,
.readdir = proc_tid_base_readdir,
};
-static struct inode_operations proc_tid_base_inode_operations = {
+static const struct inode_operations proc_tid_base_inode_operations = {
.lookup = proc_tid_base_lookup,
.getattr = pid_getattr,
.setattr = proc_setattr,
{
struct dentry *error = ERR_PTR(-ENOENT);
struct inode *inode;
- inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_INO);
+ inode = proc_pid_make_inode(dir->i_sb, task);
if (!inode)
goto 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);
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 dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
- struct task_struct *leader = get_proc_task(inode);
+ struct task_struct *leader = NULL;
struct task_struct *task;
int retval = -ENOENT;
ino_t ino;
int tid;
unsigned long pos = filp->f_pos; /* avoiding "long long" filp->f_pos */
+ task = get_proc_task(inode);
+ if (!task)
+ goto out_no_task;
+ rcu_read_lock();
+ if (pid_alive(task)) {
+ leader = task->group_leader;
+ get_task_struct(leader);
+ }
+ rcu_read_unlock();
+ put_task_struct(task);
if (!leader)
goto out_no_task;
retval = 0;
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;
return 0;
}
-static struct inode_operations proc_task_inode_operations = {
+static const struct inode_operations proc_task_inode_operations = {
.lookup = proc_task_lookup,
.getattr = proc_task_getattr,
.setattr = proc_setattr,
};
-static struct file_operations proc_task_operations = {
+static const struct file_operations proc_task_operations = {
.read = generic_read_dir,
.readdir = proc_task_readdir,
};