aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
authorRam Pai <linuxram@us.ibm.com>2008-03-27 08:06:25 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2008-04-23 00:05:03 -0400
commit2d4d4864ac08caff5c204a752bd004eed4f08760 (patch)
treea8907c33afae589146fdcd06eacd740aff48c6a1 /fs/namespace.c
parenta1a2c409b666befc58c2db9c7fbddf200f153470 (diff)
[patch 6/7] vfs: mountinfo: add /proc/<pid>/mountinfo
[mszeredi@suse.cz] rewrite and split big patch into managable chunks /proc/mounts in its current form lacks important information: - propagation state - root of mount for bind mounts - the st_dev value used within the filesystem - identifier for each mount and it's parent It also suffers from the following problems: - not easily extendable - ambiguity of mountpoints within a chrooted environment - doesn't distinguish between filesystem dependent and independent options - doesn't distinguish between per mount and per super block options This patch introduces /proc/<pid>/mountinfo which attempts to address all these deficiencies. Code shared between /proc/<pid>/mounts and /proc/<pid>/mountinfo is extracted into separate functions. Thanks to Al Viro for the help in getting the design right. Signed-off-by: Ram Pai <linuxram@us.ibm.com> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c119
1 files changed, 96 insertions, 23 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index dfdf51e81c1c..c807b8d5f891 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -746,20 +746,30 @@ static void m_stop(struct seq_file *m, void *v)
746 up_read(&namespace_sem); 746 up_read(&namespace_sem);
747} 747}
748 748
749static int show_vfsmnt(struct seq_file *m, void *v) 749struct proc_fs_info {
750 int flag;
751 const char *str;
752};
753
754static void show_sb_opts(struct seq_file *m, struct super_block *sb)
750{ 755{
751 struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); 756 static const struct proc_fs_info fs_info[] = {
752 int err = 0;
753 static struct proc_fs_info {
754 int flag;
755 char *str;
756 } fs_info[] = {
757 { MS_SYNCHRONOUS, ",sync" }, 757 { MS_SYNCHRONOUS, ",sync" },
758 { MS_DIRSYNC, ",dirsync" }, 758 { MS_DIRSYNC, ",dirsync" },
759 { MS_MANDLOCK, ",mand" }, 759 { MS_MANDLOCK, ",mand" },
760 { 0, NULL } 760 { 0, NULL }
761 }; 761 };
762 static struct proc_fs_info mnt_info[] = { 762 const struct proc_fs_info *fs_infop;
763
764 for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {
765 if (sb->s_flags & fs_infop->flag)
766 seq_puts(m, fs_infop->str);
767 }
768}
769
770static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt)
771{
772 static const struct proc_fs_info mnt_info[] = {
763 { MNT_NOSUID, ",nosuid" }, 773 { MNT_NOSUID, ",nosuid" },
764 { MNT_NODEV, ",nodev" }, 774 { MNT_NODEV, ",nodev" },
765 { MNT_NOEXEC, ",noexec" }, 775 { MNT_NOEXEC, ",noexec" },
@@ -768,27 +778,37 @@ static int show_vfsmnt(struct seq_file *m, void *v)
768 { MNT_RELATIME, ",relatime" }, 778 { MNT_RELATIME, ",relatime" },
769 { 0, NULL } 779 { 0, NULL }
770 }; 780 };
771 struct proc_fs_info *fs_infop; 781 const struct proc_fs_info *fs_infop;
782
783 for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) {
784 if (mnt->mnt_flags & fs_infop->flag)
785 seq_puts(m, fs_infop->str);
786 }
787}
788
789static void show_type(struct seq_file *m, struct super_block *sb)
790{
791 mangle(m, sb->s_type->name);
792 if (sb->s_subtype && sb->s_subtype[0]) {
793 seq_putc(m, '.');
794 mangle(m, sb->s_subtype);
795 }
796}
797
798static int show_vfsmnt(struct seq_file *m, void *v)
799{
800 struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list);
801 int err = 0;
772 struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; 802 struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
773 803
774 mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); 804 mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
775 seq_putc(m, ' '); 805 seq_putc(m, ' ');
776 seq_path(m, &mnt_path, " \t\n\\"); 806 seq_path(m, &mnt_path, " \t\n\\");
777 seq_putc(m, ' '); 807 seq_putc(m, ' ');
778 mangle(m, mnt->mnt_sb->s_type->name); 808 show_type(m, mnt->mnt_sb);
779 if (mnt->mnt_sb->s_subtype && mnt->mnt_sb->s_subtype[0]) {
780 seq_putc(m, '.');
781 mangle(m, mnt->mnt_sb->s_subtype);
782 }
783 seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw"); 809 seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw");
784 for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { 810 show_sb_opts(m, mnt->mnt_sb);
785 if (mnt->mnt_sb->s_flags & fs_infop->flag) 811 show_mnt_opts(m, mnt);
786 seq_puts(m, fs_infop->str);
787 }
788 for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) {
789 if (mnt->mnt_flags & fs_infop->flag)
790 seq_puts(m, fs_infop->str);
791 }
792 if (mnt->mnt_sb->s_op->show_options) 812 if (mnt->mnt_sb->s_op->show_options)
793 err = mnt->mnt_sb->s_op->show_options(m, mnt); 813 err = mnt->mnt_sb->s_op->show_options(m, mnt);
794 seq_puts(m, " 0 0\n"); 814 seq_puts(m, " 0 0\n");
@@ -802,6 +822,59 @@ const struct seq_operations mounts_op = {
802 .show = show_vfsmnt 822 .show = show_vfsmnt
803}; 823};
804 824
825static int show_mountinfo(struct seq_file *m, void *v)
826{
827 struct proc_mounts *p = m->private;
828 struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list);
829 struct super_block *sb = mnt->mnt_sb;
830 struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
831 struct path root = p->root;
832 int err = 0;
833
834 seq_printf(m, "%i %i %u:%u ", mnt->mnt_id, mnt->mnt_parent->mnt_id,
835 MAJOR(sb->s_dev), MINOR(sb->s_dev));
836 seq_dentry(m, mnt->mnt_root, " \t\n\\");
837 seq_putc(m, ' ');
838 seq_path_root(m, &mnt_path, &root, " \t\n\\");
839 if (root.mnt != p->root.mnt || root.dentry != p->root.dentry) {
840 /*
841 * Mountpoint is outside root, discard that one. Ugly,
842 * but less so than trying to do that in iterator in a
843 * race-free way (due to renames).
844 */
845 return SEQ_SKIP;
846 }
847 seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw");
848 show_mnt_opts(m, mnt);
849
850 /* Tagged fields ("foo:X" or "bar") */
851 if (IS_MNT_SHARED(mnt))
852 seq_printf(m, " shared:%i", mnt->mnt_group_id);
853 if (IS_MNT_SLAVE(mnt))
854 seq_printf(m, " master:%i", mnt->mnt_master->mnt_group_id);
855 if (IS_MNT_UNBINDABLE(mnt))
856 seq_puts(m, " unbindable");
857
858 /* Filesystem specific data */
859 seq_puts(m, " - ");
860 show_type(m, sb);
861 seq_putc(m, ' ');
862 mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
863 seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw");
864 show_sb_opts(m, sb);
865 if (sb->s_op->show_options)
866 err = sb->s_op->show_options(m, mnt);
867 seq_putc(m, '\n');
868 return err;
869}
870
871const struct seq_operations mountinfo_op = {
872 .start = m_start,
873 .next = m_next,
874 .stop = m_stop,
875 .show = show_mountinfo,
876};
877
805static int show_vfsstat(struct seq_file *m, void *v) 878static int show_vfsstat(struct seq_file *m, void *v)
806{ 879{
807 struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); 880 struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list);
@@ -822,7 +895,7 @@ static int show_vfsstat(struct seq_file *m, void *v)
822 895
823 /* file system type */ 896 /* file system type */
824 seq_puts(m, "with fstype "); 897 seq_puts(m, "with fstype ");
825 mangle(m, mnt->mnt_sb->s_type->name); 898 show_type(m, mnt->mnt_sb);
826 899
827 /* optional statistics */ 900 /* optional statistics */
828 if (mnt->mnt_sb->s_op->show_stats) { 901 if (mnt->mnt_sb->s_op->show_stats) {