[patch 5/7] vfs: mountinfo: allow using process root
Allow /proc/<pid>/mountinfo to use the root of <pid> to calculate mountpoints. - move definition of 'struct proc_mounts' to <linux/mnt_namespace.h> - add the process's namespace and root to this structure - pass a pointer to 'struct proc_mounts' into seq_operations In addition the following cleanups are made: - use a common open function for /proc/<pid>/{mounts,mountstat} - surround namespace.c part of these proc files with #ifdef CONFIG_PROC_FS - make the seq_operations structures const Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
719f5d7f0b
commit
a1a2c409b6
|
@ -724,20 +724,21 @@ void save_mount_options(struct super_block *sb, char *options)
|
|||
}
|
||||
EXPORT_SYMBOL(save_mount_options);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
/* iterator */
|
||||
static void *m_start(struct seq_file *m, loff_t *pos)
|
||||
{
|
||||
struct mnt_namespace *n = m->private;
|
||||
struct proc_mounts *p = m->private;
|
||||
|
||||
down_read(&namespace_sem);
|
||||
return seq_list_start(&n->list, *pos);
|
||||
return seq_list_start(&p->ns->list, *pos);
|
||||
}
|
||||
|
||||
static void *m_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
{
|
||||
struct mnt_namespace *n = m->private;
|
||||
struct proc_mounts *p = m->private;
|
||||
|
||||
return seq_list_next(v, &n->list, pos);
|
||||
return seq_list_next(v, &p->ns->list, pos);
|
||||
}
|
||||
|
||||
static void m_stop(struct seq_file *m, void *v)
|
||||
|
@ -794,7 +795,7 @@ static int show_vfsmnt(struct seq_file *m, void *v)
|
|||
return err;
|
||||
}
|
||||
|
||||
struct seq_operations mounts_op = {
|
||||
const struct seq_operations mounts_op = {
|
||||
.start = m_start,
|
||||
.next = m_next,
|
||||
.stop = m_stop,
|
||||
|
@ -833,12 +834,13 @@ static int show_vfsstat(struct seq_file *m, void *v)
|
|||
return err;
|
||||
}
|
||||
|
||||
struct seq_operations mountstats_op = {
|
||||
const struct seq_operations mountstats_op = {
|
||||
.start = m_start,
|
||||
.next = m_next,
|
||||
.stop = m_stop,
|
||||
.show = show_vfsstat,
|
||||
};
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
/**
|
||||
* may_umount_tree - check if a mount tree is busy
|
||||
|
|
108
fs/proc/base.c
108
fs/proc/base.c
|
@ -502,17 +502,14 @@ static const struct inode_operations proc_def_inode_operations = {
|
|||
.setattr = proc_setattr,
|
||||
};
|
||||
|
||||
extern const struct seq_operations mounts_op;
|
||||
struct proc_mounts {
|
||||
struct seq_file m;
|
||||
int event;
|
||||
};
|
||||
|
||||
static int mounts_open(struct inode *inode, struct file *file)
|
||||
static int mounts_open_common(struct inode *inode, struct file *file,
|
||||
const struct seq_operations *op)
|
||||
{
|
||||
struct task_struct *task = get_proc_task(inode);
|
||||
struct nsproxy *nsp;
|
||||
struct mnt_namespace *ns = NULL;
|
||||
struct fs_struct *fs = NULL;
|
||||
struct path root;
|
||||
struct proc_mounts *p;
|
||||
int ret = -EINVAL;
|
||||
|
||||
|
@ -525,40 +522,61 @@ static int mounts_open(struct inode *inode, struct file *file)
|
|||
get_mnt_ns(ns);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (ns)
|
||||
fs = get_fs_struct(task);
|
||||
put_task_struct(task);
|
||||
}
|
||||
|
||||
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 = ns;
|
||||
p->event = ns->event;
|
||||
return 0;
|
||||
}
|
||||
kfree(p);
|
||||
}
|
||||
put_mnt_ns(ns);
|
||||
}
|
||||
if (!ns)
|
||||
goto err;
|
||||
if (!fs)
|
||||
goto err_put_ns;
|
||||
|
||||
read_lock(&fs->lock);
|
||||
root = fs->root;
|
||||
path_get(&root);
|
||||
read_unlock(&fs->lock);
|
||||
put_fs_struct(fs);
|
||||
|
||||
ret = -ENOMEM;
|
||||
p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
|
||||
if (!p)
|
||||
goto err_put_path;
|
||||
|
||||
file->private_data = &p->m;
|
||||
ret = seq_open(file, op);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
p->m.private = p;
|
||||
p->ns = ns;
|
||||
p->root = root;
|
||||
p->event = ns->event;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
kfree(p);
|
||||
err_put_path:
|
||||
path_put(&root);
|
||||
err_put_ns:
|
||||
put_mnt_ns(ns);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mounts_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct seq_file *m = file->private_data;
|
||||
struct mnt_namespace *ns = m->private;
|
||||
put_mnt_ns(ns);
|
||||
struct proc_mounts *p = file->private_data;
|
||||
path_put(&p->root);
|
||||
put_mnt_ns(p->ns);
|
||||
return seq_release(inode, file);
|
||||
}
|
||||
|
||||
static unsigned mounts_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct proc_mounts *p = file->private_data;
|
||||
struct mnt_namespace *ns = p->m.private;
|
||||
struct mnt_namespace *ns = p->ns;
|
||||
unsigned res = 0;
|
||||
|
||||
poll_wait(file, &ns->poll, wait);
|
||||
|
@ -573,6 +591,11 @@ static unsigned mounts_poll(struct file *file, poll_table *wait)
|
|||
return res;
|
||||
}
|
||||
|
||||
static int mounts_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return mounts_open_common(inode, file, &mounts_op);
|
||||
}
|
||||
|
||||
static const struct file_operations proc_mounts_operations = {
|
||||
.open = mounts_open,
|
||||
.read = seq_read,
|
||||
|
@ -581,38 +604,9 @@ static const struct file_operations proc_mounts_operations = {
|
|||
.poll = mounts_poll,
|
||||
};
|
||||
|
||||
extern const struct seq_operations mountstats_op;
|
||||
static int mountstats_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
int ret = seq_open(file, &mountstats_op);
|
||||
|
||||
if (!ret) {
|
||||
struct seq_file *m = file->private_data;
|
||||
struct nsproxy *nsp;
|
||||
struct mnt_namespace *mnt_ns = NULL;
|
||||
struct task_struct *task = get_proc_task(inode);
|
||||
|
||||
if (task) {
|
||||
rcu_read_lock();
|
||||
nsp = task_nsproxy(task);
|
||||
if (nsp) {
|
||||
mnt_ns = nsp->mnt_ns;
|
||||
if (mnt_ns)
|
||||
get_mnt_ns(mnt_ns);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
put_task_struct(task);
|
||||
}
|
||||
|
||||
if (mnt_ns)
|
||||
m->private = mnt_ns;
|
||||
else {
|
||||
seq_release(inode, file);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
return mounts_open_common(inode, file, &mountstats_op);
|
||||
}
|
||||
|
||||
static const struct file_operations proc_mountstats_operations = {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <linux/mount.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/nsproxy.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
struct mnt_namespace {
|
||||
atomic_t count;
|
||||
|
@ -14,6 +15,13 @@ struct mnt_namespace {
|
|||
int event;
|
||||
};
|
||||
|
||||
struct proc_mounts {
|
||||
struct seq_file m; /* must be the first element */
|
||||
struct mnt_namespace *ns;
|
||||
struct path root;
|
||||
int event;
|
||||
};
|
||||
|
||||
extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *,
|
||||
struct fs_struct *);
|
||||
extern void __put_mnt_ns(struct mnt_namespace *ns);
|
||||
|
@ -37,5 +45,8 @@ static inline void get_mnt_ns(struct mnt_namespace *ns)
|
|||
atomic_inc(&ns->count);
|
||||
}
|
||||
|
||||
extern const struct seq_operations mounts_op;
|
||||
extern const struct seq_operations mountstats_op;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue