summaryrefslogtreecommitdiffstats
path: root/fs/proc/base.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r--fs/proc/base.c183
1 files changed, 95 insertions, 88 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 33537487f5a..88f8edf1825 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -88,10 +88,6 @@
* in /proc for a task before it execs a suid executable.
*/
-
-/* Worst case buffer size needed for holding an integer. */
-#define PROC_NUMBUF 13
-
struct pid_entry {
char *name;
int len;
@@ -125,6 +121,10 @@ struct pid_entry {
NOD(NAME, (S_IFREG|(MODE)), \
NULL, &proc_info_file_operations, \
{ .proc_read = &proc_##OTYPE } )
+#define ONE(NAME, MODE, OTYPE) \
+ NOD(NAME, (S_IFREG|(MODE)), \
+ NULL, &proc_single_file_operations, \
+ { .proc_show = &proc_##OTYPE } )
int maps_protect;
EXPORT_SYMBOL(maps_protect);
@@ -153,7 +153,7 @@ static int get_nr_threads(struct task_struct *tsk)
return count;
}
-static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+static int proc_cwd_link(struct inode *inode, struct path *path)
{
struct task_struct *task = get_proc_task(inode);
struct fs_struct *fs = NULL;
@@ -165,8 +165,8 @@ static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfs
}
if (fs) {
read_lock(&fs->lock);
- *mnt = mntget(fs->pwdmnt);
- *dentry = dget(fs->pwd);
+ *path = fs->pwd;
+ path_get(&fs->pwd);
read_unlock(&fs->lock);
result = 0;
put_fs_struct(fs);
@@ -174,7 +174,7 @@ static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfs
return result;
}
-static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+static int proc_root_link(struct inode *inode, struct path *path)
{
struct task_struct *task = get_proc_task(inode);
struct fs_struct *fs = NULL;
@@ -186,8 +186,8 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf
}
if (fs) {
read_lock(&fs->lock);
- *mnt = mntget(fs->rootmnt);
- *dentry = dget(fs->root);
+ *path = fs->root;
+ path_get(&fs->root);
read_unlock(&fs->lock);
result = 0;
put_fs_struct(fs);
@@ -506,7 +506,7 @@ static const struct inode_operations proc_def_inode_operations = {
.setattr = proc_setattr,
};
-extern struct seq_operations mounts_op;
+extern const struct seq_operations mounts_op;
struct proc_mounts {
struct seq_file m;
int event;
@@ -585,7 +585,7 @@ static const struct file_operations proc_mounts_operations = {
.poll = mounts_poll,
};
-extern struct seq_operations mountstats_op;
+extern const struct seq_operations mountstats_op;
static int mountstats_open(struct inode *inode, struct file *file)
{
int ret = seq_open(file, &mountstats_op);
@@ -662,6 +662,45 @@ static const struct file_operations proc_info_file_operations = {
.read = proc_info_read,
};
+static int proc_single_show(struct seq_file *m, void *v)
+{
+ struct inode *inode = m->private;
+ struct pid_namespace *ns;
+ struct pid *pid;
+ struct task_struct *task;
+ int ret;
+
+ ns = inode->i_sb->s_fs_info;
+ pid = proc_pid(inode);
+ task = get_pid_task(pid, PIDTYPE_PID);
+ if (!task)
+ return -ESRCH;
+
+ ret = PROC_I(inode)->op.proc_show(m, ns, pid, task);
+
+ put_task_struct(task);
+ return ret;
+}
+
+static int proc_single_open(struct inode *inode, struct file *filp)
+{
+ int ret;
+ ret = single_open(filp, proc_single_show, NULL);
+ if (!ret) {
+ struct seq_file *m = filp->private_data;
+
+ m->private = inode;
+ }
+ return ret;
+}
+
+static const struct file_operations proc_single_file_operations = {
+ .open = proc_single_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static int mem_open(struct inode* inode, struct file* file)
{
file->private_data = (void*)((long)current->self_exec_id);
@@ -787,7 +826,7 @@ out_no_task:
}
#endif
-static loff_t mem_lseek(struct file * file, loff_t offset, int orig)
+loff_t mem_lseek(struct file *file, loff_t offset, int orig)
{
switch (orig) {
case 0:
@@ -935,42 +974,6 @@ static const struct file_operations proc_oom_adjust_operations = {
.write = oom_adjust_write,
};
-#ifdef CONFIG_MMU
-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,
-};
-#endif
-
#ifdef CONFIG_AUDITSYSCALL
#define TMPBUFLEN 21
static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
@@ -1161,39 +1164,36 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
int error = -EACCES;
/* We don't need a base pointer in the /proc filesystem */
- path_release(nd);
+ path_put(&nd->path);
/* Are we allowed to snoop on the tasks file descriptors? */
if (!proc_fd_access_allowed(inode))
goto out;
- error = PROC_I(inode)->op.proc_get_link(inode, &nd->dentry, &nd->mnt);
+ error = PROC_I(inode)->op.proc_get_link(inode, &nd->path);
nd->last_type = LAST_BIND;
out:
return ERR_PTR(error);
}
-static int do_proc_readlink(struct dentry *dentry, struct vfsmount *mnt,
- char __user *buffer, int buflen)
+static int do_proc_readlink(struct path *path, char __user *buffer, int buflen)
{
- struct inode * inode;
char *tmp = (char*)__get_free_page(GFP_TEMPORARY);
- char *path;
+ char *pathname;
int len;
if (!tmp)
return -ENOMEM;
- inode = dentry->d_inode;
- path = d_path(dentry, mnt, tmp, PAGE_SIZE);
- len = PTR_ERR(path);
- if (IS_ERR(path))
+ pathname = d_path(path, tmp, PAGE_SIZE);
+ len = PTR_ERR(pathname);
+ if (IS_ERR(pathname))
goto out;
- len = tmp + PAGE_SIZE - 1 - path;
+ len = tmp + PAGE_SIZE - 1 - pathname;
if (len > buflen)
len = buflen;
- if (copy_to_user(buffer, path, len))
+ if (copy_to_user(buffer, pathname, len))
len = -EFAULT;
out:
free_page((unsigned long)tmp);
@@ -1204,20 +1204,18 @@ static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int b
{
int error = -EACCES;
struct inode *inode = dentry->d_inode;
- struct dentry *de;
- struct vfsmount *mnt = NULL;
+ struct path path;
/* Are we allowed to snoop on the tasks file descriptors? */
if (!proc_fd_access_allowed(inode))
goto out;
- error = PROC_I(inode)->op.proc_get_link(inode, &de, &mnt);
+ error = PROC_I(inode)->op.proc_get_link(inode, &path);
if (error)
goto out;
- error = do_proc_readlink(de, mnt, buffer, buflen);
- dput(de);
- mntput(mnt);
+ error = do_proc_readlink(&path, buffer, buflen);
+ path_put(&path);
out:
return error;
}
@@ -1444,8 +1442,7 @@ out:
#define PROC_FDINFO_MAX 64
-static int proc_fd_info(struct inode *inode, struct dentry **dentry,
- struct vfsmount **mnt, char *info)
+static int proc_fd_info(struct inode *inode, struct path *path, char *info)
{
struct task_struct *task = get_proc_task(inode);
struct files_struct *files = NULL;
@@ -1464,10 +1461,10 @@ static int proc_fd_info(struct inode *inode, struct dentry **dentry,
spin_lock(&files->file_lock);
file = fcheck_files(files, fd);
if (file) {
- if (mnt)
- *mnt = mntget(file->f_path.mnt);
- if (dentry)
- *dentry = dget(file->f_path.dentry);
+ if (path) {
+ *path = file->f_path;
+ path_get(&file->f_path);
+ }
if (info)
snprintf(info, PROC_FDINFO_MAX,
"pos:\t%lli\n"
@@ -1484,10 +1481,9 @@ static int proc_fd_info(struct inode *inode, struct dentry **dentry,
return -ENOENT;
}
-static int proc_fd_link(struct inode *inode, struct dentry **dentry,
- struct vfsmount **mnt)
+static int proc_fd_link(struct inode *inode, struct path *path)
{
- return proc_fd_info(inode, dentry, mnt, NULL);
+ return proc_fd_info(inode, path, NULL);
}
static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
@@ -1681,7 +1677,7 @@ 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);
+ int err = proc_fd_info(file->f_path.dentry->d_inode, NULL, tmp);
if (!err)
err = simple_read_from_buffer(buf, len, ppos, tmp, strlen(tmp));
return err;
@@ -2098,15 +2094,23 @@ static const struct file_operations proc_coredump_filter_operations = {
static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
int buflen)
{
+ struct pid_namespace *ns = dentry->d_sb->s_fs_info;
+ pid_t tgid = task_tgid_nr_ns(current, ns);
char tmp[PROC_NUMBUF];
- sprintf(tmp, "%d", task_tgid_vnr(current));
+ if (!tgid)
+ return -ENOENT;
+ sprintf(tmp, "%d", tgid);
return vfs_readlink(dentry,buffer,buflen,tmp);
}
static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
{
+ struct pid_namespace *ns = dentry->d_sb->s_fs_info;
+ pid_t tgid = task_tgid_nr_ns(current, ns);
char tmp[PROC_NUMBUF];
- sprintf(tmp, "%d", task_tgid_vnr(current));
+ if (!tgid)
+ return ERR_PTR(-ENOENT);
+ sprintf(tmp, "%d", task_tgid_nr_ns(current, ns));
return ERR_PTR(vfs_follow_link(nd,tmp));
}
@@ -2271,14 +2275,14 @@ static const struct pid_entry tgid_base_stuff[] = {
DIR("fdinfo", S_IRUSR|S_IXUSR, fdinfo),
REG("environ", S_IRUSR, environ),
INF("auxv", S_IRUSR, pid_auxv),
- INF("status", S_IRUGO, pid_status),
+ ONE("status", S_IRUGO, pid_status),
INF("limits", S_IRUSR, pid_limits),
#ifdef CONFIG_SCHED_DEBUG
REG("sched", S_IRUGO|S_IWUSR, pid_sched),
#endif
INF("cmdline", S_IRUGO, pid_cmdline),
- INF("stat", S_IRUGO, tgid_stat),
- INF("statm", S_IRUGO, pid_statm),
+ ONE("stat", S_IRUGO, tgid_stat),
+ ONE("statm", S_IRUGO, pid_statm),
REG("maps", S_IRUGO, maps),
#ifdef CONFIG_NUMA
REG("numa_maps", S_IRUGO, numa_maps),
@@ -2289,9 +2293,10 @@ static const struct pid_entry tgid_base_stuff[] = {
LNK("exe", exe),
REG("mounts", S_IRUGO, mounts),
REG("mountstats", S_IRUSR, mountstats),
-#ifdef CONFIG_MMU
+#ifdef CONFIG_PROC_PAGE_MONITOR
REG("clear_refs", S_IWUSR, clear_refs),
REG("smaps", S_IRUGO, smaps),
+ REG("pagemap", S_IRUSR, pagemap),
#endif
#ifdef CONFIG_SECURITY
DIR("attr", S_IRUGO|S_IXUGO, attr_dir),
@@ -2360,7 +2365,8 @@ static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid)
name.len = snprintf(buf, sizeof(buf), "%d", pid);
dentry = d_hash_and_lookup(mnt->mnt_root, &name);
if (dentry) {
- shrink_dcache_parent(dentry);
+ if (!(current->flags & PF_EXITING))
+ shrink_dcache_parent(dentry);
d_drop(dentry);
dput(dentry);
}
@@ -2600,14 +2606,14 @@ static const struct pid_entry tid_base_stuff[] = {
DIR("fdinfo", S_IRUSR|S_IXUSR, fdinfo),
REG("environ", S_IRUSR, environ),
INF("auxv", S_IRUSR, pid_auxv),
- INF("status", S_IRUGO, pid_status),
+ ONE("status", S_IRUGO, pid_status),
INF("limits", S_IRUSR, pid_limits),
#ifdef CONFIG_SCHED_DEBUG
REG("sched", S_IRUGO|S_IWUSR, pid_sched),
#endif
INF("cmdline", S_IRUGO, pid_cmdline),
- INF("stat", S_IRUGO, tid_stat),
- INF("statm", S_IRUGO, pid_statm),
+ ONE("stat", S_IRUGO, tid_stat),
+ ONE("statm", S_IRUGO, pid_statm),
REG("maps", S_IRUGO, maps),
#ifdef CONFIG_NUMA
REG("numa_maps", S_IRUGO, numa_maps),
@@ -2617,9 +2623,10 @@ static const struct pid_entry tid_base_stuff[] = {
LNK("root", root),
LNK("exe", exe),
REG("mounts", S_IRUGO, mounts),
-#ifdef CONFIG_MMU
+#ifdef CONFIG_PROC_PAGE_MONITOR
REG("clear_refs", S_IWUSR, clear_refs),
REG("smaps", S_IRUGO, smaps),
+ REG("pagemap", S_IRUSR, pagemap),
#endif
#ifdef CONFIG_SECURITY
DIR("attr", S_IRUGO|S_IXUGO, attr_dir),