Commit b4629fe2 authored by Chuck Lever's avatar Chuck Lever Committed by Trond Myklebust

VFS: New /proc file /proc/self/mountstats

Create a new file under /proc/self, called mountstats, where mounted file
systems can export information (configuration options, performance counters,
and so on).  Use a mechanism similar to /proc/mounts and s_ops->show_options.

This mechanism does not violate namespace security, and is safe to use while
other processes are unmounting file systems.

Thanks to Mike Waychison for his review and comments.

Test-plan:
Test concurrent mount/unmount operations while cat'ing /proc/self/mountstats.
Signed-off-by: default avatarChuck Lever <cel@netapp.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 1356b8c2
...@@ -399,6 +399,44 @@ struct seq_operations mounts_op = { ...@@ -399,6 +399,44 @@ struct seq_operations mounts_op = {
.show = show_vfsmnt .show = show_vfsmnt
}; };
static int show_vfsstat(struct seq_file *m, void *v)
{
struct vfsmount *mnt = v;
int err = 0;
/* device */
if (mnt->mnt_devname) {
seq_puts(m, "device ");
mangle(m, mnt->mnt_devname);
} else
seq_puts(m, "no device");
/* mount point */
seq_puts(m, " mounted on ");
seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
seq_putc(m, ' ');
/* file system type */
seq_puts(m, "with fstype ");
mangle(m, mnt->mnt_sb->s_type->name);
/* optional statistics */
if (mnt->mnt_sb->s_op->show_stats) {
seq_putc(m, ' ');
err = mnt->mnt_sb->s_op->show_stats(m, mnt);
}
seq_putc(m, '\n');
return err;
}
struct seq_operations mountstats_op = {
.start = m_start,
.next = m_next,
.stop = m_stop,
.show = show_vfsstat,
};
/** /**
* may_umount_tree - check if a mount tree is busy * may_umount_tree - check if a mount tree is busy
* @mnt: root of mount tree * @mnt: root of mount tree
......
...@@ -104,6 +104,7 @@ enum pid_directory_inos { ...@@ -104,6 +104,7 @@ enum pid_directory_inos {
PROC_TGID_MAPS, PROC_TGID_MAPS,
PROC_TGID_NUMA_MAPS, PROC_TGID_NUMA_MAPS,
PROC_TGID_MOUNTS, PROC_TGID_MOUNTS,
PROC_TGID_MOUNTSTATS,
PROC_TGID_WCHAN, PROC_TGID_WCHAN,
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
PROC_TGID_SMAPS, PROC_TGID_SMAPS,
...@@ -144,6 +145,7 @@ enum pid_directory_inos { ...@@ -144,6 +145,7 @@ enum pid_directory_inos {
PROC_TID_MAPS, PROC_TID_MAPS,
PROC_TID_NUMA_MAPS, PROC_TID_NUMA_MAPS,
PROC_TID_MOUNTS, PROC_TID_MOUNTS,
PROC_TID_MOUNTSTATS,
PROC_TID_WCHAN, PROC_TID_WCHAN,
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
PROC_TID_SMAPS, PROC_TID_SMAPS,
...@@ -201,6 +203,7 @@ static struct pid_entry tgid_base_stuff[] = { ...@@ -201,6 +203,7 @@ static struct pid_entry tgid_base_stuff[] = {
E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO), E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO),
E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO), E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO),
E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO), E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO),
E(PROC_TGID_MOUNTSTATS, "mountstats", S_IFREG|S_IRUSR),
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO), E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO),
#endif #endif
...@@ -732,6 +735,38 @@ static struct file_operations proc_mounts_operations = { ...@@ -732,6 +735,38 @@ static struct file_operations proc_mounts_operations = {
.poll = mounts_poll, .poll = mounts_poll,
}; };
extern struct seq_operations mountstats_op;
static int mountstats_open(struct inode *inode, struct file *file)
{
struct task_struct *task = proc_task(inode);
int ret = seq_open(file, &mountstats_op);
if (!ret) {
struct seq_file *m = file->private_data;
struct namespace *namespace;
task_lock(task);
namespace = task->namespace;
if (namespace)
get_namespace(namespace);
task_unlock(task);
if (namespace)
m->private = namespace;
else {
seq_release(inode, file);
ret = -EINVAL;
}
}
return ret;
}
static struct file_operations proc_mountstats_operations = {
.open = mountstats_open,
.read = seq_read,
.llseek = seq_lseek,
.release = mounts_release,
};
#define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ #define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */
static ssize_t proc_info_read(struct file * file, char __user * buf, static ssize_t proc_info_read(struct file * file, char __user * buf,
...@@ -1730,6 +1765,10 @@ static struct dentry *proc_pident_lookup(struct inode *dir, ...@@ -1730,6 +1765,10 @@ static struct dentry *proc_pident_lookup(struct inode *dir,
inode->i_fop = &proc_smaps_operations; inode->i_fop = &proc_smaps_operations;
break; break;
#endif #endif
case PROC_TID_MOUNTSTATS:
case PROC_TGID_MOUNTSTATS:
inode->i_fop = &proc_mountstats_operations;
break;
#ifdef CONFIG_SECURITY #ifdef CONFIG_SECURITY
case PROC_TID_ATTR: case PROC_TID_ATTR:
inode->i_nlink = 2; inode->i_nlink = 2;
......
...@@ -1086,6 +1086,7 @@ struct super_operations { ...@@ -1086,6 +1086,7 @@ struct super_operations {
void (*umount_begin) (struct super_block *); void (*umount_begin) (struct super_block *);
int (*show_options)(struct seq_file *, struct vfsmount *); int (*show_options)(struct seq_file *, struct vfsmount *);
int (*show_stats)(struct seq_file *, struct vfsmount *);
ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t); ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment