forked from Minki/linux
[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);
|
EXPORT_SYMBOL(save_mount_options);
|
||||||
|
|
||||||
|
#ifdef CONFIG_PROC_FS
|
||||||
/* iterator */
|
/* iterator */
|
||||||
static void *m_start(struct seq_file *m, loff_t *pos)
|
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);
|
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)
|
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)
|
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;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct seq_operations mounts_op = {
|
const struct seq_operations mounts_op = {
|
||||||
.start = m_start,
|
.start = m_start,
|
||||||
.next = m_next,
|
.next = m_next,
|
||||||
.stop = m_stop,
|
.stop = m_stop,
|
||||||
|
@ -833,12 +834,13 @@ static int show_vfsstat(struct seq_file *m, void *v)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct seq_operations mountstats_op = {
|
const struct seq_operations mountstats_op = {
|
||||||
.start = m_start,
|
.start = m_start,
|
||||||
.next = m_next,
|
.next = m_next,
|
||||||
.stop = m_stop,
|
.stop = m_stop,
|
||||||
.show = show_vfsstat,
|
.show = show_vfsstat,
|
||||||
};
|
};
|
||||||
|
#endif /* CONFIG_PROC_FS */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* may_umount_tree - check if a mount tree is busy
|
* 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,
|
.setattr = proc_setattr,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const struct seq_operations mounts_op;
|
static int mounts_open_common(struct inode *inode, struct file *file,
|
||||||
struct proc_mounts {
|
const struct seq_operations *op)
|
||||||
struct seq_file m;
|
|
||||||
int event;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int mounts_open(struct inode *inode, struct file *file)
|
|
||||||
{
|
{
|
||||||
struct task_struct *task = get_proc_task(inode);
|
struct task_struct *task = get_proc_task(inode);
|
||||||
struct nsproxy *nsp;
|
struct nsproxy *nsp;
|
||||||
struct mnt_namespace *ns = NULL;
|
struct mnt_namespace *ns = NULL;
|
||||||
|
struct fs_struct *fs = NULL;
|
||||||
|
struct path root;
|
||||||
struct proc_mounts *p;
|
struct proc_mounts *p;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
@ -525,40 +522,61 @@ static int mounts_open(struct inode *inode, struct file *file)
|
||||||
get_mnt_ns(ns);
|
get_mnt_ns(ns);
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
if (ns)
|
||||||
|
fs = get_fs_struct(task);
|
||||||
put_task_struct(task);
|
put_task_struct(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ns) {
|
if (!ns)
|
||||||
ret = -ENOMEM;
|
goto err;
|
||||||
p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
|
if (!fs)
|
||||||
if (p) {
|
goto err_put_ns;
|
||||||
file->private_data = &p->m;
|
|
||||||
ret = seq_open(file, &mounts_op);
|
read_lock(&fs->lock);
|
||||||
if (!ret) {
|
root = fs->root;
|
||||||
p->m.private = ns;
|
path_get(&root);
|
||||||
p->event = ns->event;
|
read_unlock(&fs->lock);
|
||||||
return 0;
|
put_fs_struct(fs);
|
||||||
}
|
|
||||||
kfree(p);
|
ret = -ENOMEM;
|
||||||
}
|
p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
|
||||||
put_mnt_ns(ns);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mounts_release(struct inode *inode, struct file *file)
|
static int mounts_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct seq_file *m = file->private_data;
|
struct proc_mounts *p = file->private_data;
|
||||||
struct mnt_namespace *ns = m->private;
|
path_put(&p->root);
|
||||||
put_mnt_ns(ns);
|
put_mnt_ns(p->ns);
|
||||||
return seq_release(inode, file);
|
return seq_release(inode, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned mounts_poll(struct file *file, poll_table *wait)
|
static unsigned mounts_poll(struct file *file, poll_table *wait)
|
||||||
{
|
{
|
||||||
struct proc_mounts *p = file->private_data;
|
struct proc_mounts *p = file->private_data;
|
||||||
struct mnt_namespace *ns = p->m.private;
|
struct mnt_namespace *ns = p->ns;
|
||||||
unsigned res = 0;
|
unsigned res = 0;
|
||||||
|
|
||||||
poll_wait(file, &ns->poll, wait);
|
poll_wait(file, &ns->poll, wait);
|
||||||
|
@ -573,6 +591,11 @@ static unsigned mounts_poll(struct file *file, poll_table *wait)
|
||||||
return res;
|
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 = {
|
static const struct file_operations proc_mounts_operations = {
|
||||||
.open = mounts_open,
|
.open = mounts_open,
|
||||||
.read = seq_read,
|
.read = seq_read,
|
||||||
|
@ -581,38 +604,9 @@ static const struct file_operations proc_mounts_operations = {
|
||||||
.poll = mounts_poll,
|
.poll = mounts_poll,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const struct seq_operations mountstats_op;
|
|
||||||
static int mountstats_open(struct inode *inode, struct file *file)
|
static int mountstats_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
int ret = seq_open(file, &mountstats_op);
|
return mounts_open_common(inode, 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations proc_mountstats_operations = {
|
static const struct file_operations proc_mountstats_operations = {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <linux/mount.h>
|
#include <linux/mount.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/nsproxy.h>
|
#include <linux/nsproxy.h>
|
||||||
|
#include <linux/seq_file.h>
|
||||||
|
|
||||||
struct mnt_namespace {
|
struct mnt_namespace {
|
||||||
atomic_t count;
|
atomic_t count;
|
||||||
|
@ -14,6 +15,13 @@ struct mnt_namespace {
|
||||||
int event;
|
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 *,
|
extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *,
|
||||||
struct fs_struct *);
|
struct fs_struct *);
|
||||||
extern void __put_mnt_ns(struct mnt_namespace *ns);
|
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);
|
atomic_inc(&ns->count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern const struct seq_operations mounts_op;
|
||||||
|
extern const struct seq_operations mountstats_op;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue
Block a user