aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-04-23 15:24:19 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-23 15:24:19 -0400
commit79c1cb7a8ca8f08cd78f7c5eebc85bbe937f5ad4 (patch)
tree0dafecbb8f729aed249e5ff66daa21a6136759c6
parentb0d19a378a409373244088511e889957645f2a44 (diff)
parent97e7e0f71d6d948c25f11f0a33878d9356d9579e (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: [patch 7/7] vfs: mountinfo: show dominating group id [patch 6/7] vfs: mountinfo: add /proc/<pid>/mountinfo [patch 5/7] vfs: mountinfo: allow using process root [patch 4/7] vfs: mountinfo: add mount peer group ID [patch 3/7] vfs: mountinfo: add mount ID [patch 2/7] vfs: mountinfo: add seq_file_root() [patch 1/7] vfs: mountinfo: add dentry_path() [PATCH] remove unused label in xattr.c (noise from ro-bind)
-rw-r--r--Documentation/filesystems/proc.txt38
-rw-r--r--fs/dcache.c114
-rw-r--r--fs/namespace.c265
-rw-r--r--fs/pnode.c56
-rw-r--r--fs/pnode.h1
-rw-r--r--fs/proc/base.c121
-rw-r--r--fs/seq_file.c95
-rw-r--r--fs/xattr.c1
-rw-r--r--include/linux/dcache.h2
-rw-r--r--include/linux/mnt_namespace.h12
-rw-r--r--include/linux/mount.h2
-rw-r--r--include/linux/seq_file.h4
12 files changed, 573 insertions, 138 deletions
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 518ebe609e2b..2a99116edc47 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -43,6 +43,7 @@ Table of Contents
43 2.13 /proc/<pid>/oom_score - Display current oom-killer score 43 2.13 /proc/<pid>/oom_score - Display current oom-killer score
44 2.14 /proc/<pid>/io - Display the IO accounting fields 44 2.14 /proc/<pid>/io - Display the IO accounting fields
45 2.15 /proc/<pid>/coredump_filter - Core dump filtering settings 45 2.15 /proc/<pid>/coredump_filter - Core dump filtering settings
46 2.16 /proc/<pid>/mountinfo - Information about mounts
46 47
47------------------------------------------------------------------------------ 48------------------------------------------------------------------------------
48Preface 49Preface
@@ -2348,4 +2349,41 @@ For example:
2348 $ echo 0x7 > /proc/self/coredump_filter 2349 $ echo 0x7 > /proc/self/coredump_filter
2349 $ ./some_program 2350 $ ./some_program
2350 2351
23522.16 /proc/<pid>/mountinfo - Information about mounts
2353--------------------------------------------------------
2354
2355This file contains lines of the form:
2356
235736 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
2358(1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
2359
2360(1) mount ID: unique identifier of the mount (may be reused after umount)
2361(2) parent ID: ID of parent (or of self for the top of the mount tree)
2362(3) major:minor: value of st_dev for files on filesystem
2363(4) root: root of the mount within the filesystem
2364(5) mount point: mount point relative to the process's root
2365(6) mount options: per mount options
2366(7) optional fields: zero or more fields of the form "tag[:value]"
2367(8) separator: marks the end of the optional fields
2368(9) filesystem type: name of filesystem of the form "type[.subtype]"
2369(10) mount source: filesystem specific information or "none"
2370(11) super options: per super block options
2371
2372Parsers should ignore all unrecognised optional fields. Currently the
2373possible optional fields are:
2374
2375shared:X mount is shared in peer group X
2376master:X mount is slave to peer group X
2377propagate_from:X mount is slave and receives propagation from peer group X (*)
2378unbindable mount is unbindable
2379
2380(*) X is the closest dominant peer group under the process's root. If
2381X is the immediate master of the mount, or if there's no dominant peer
2382group under the same root, then only the "master:X" field is present
2383and not the "propagate_from:X" field.
2384
2385For more information on mount propagation see:
2386
2387 Documentation/filesystems/sharedsubtree.txt
2388
2351------------------------------------------------------------------------------ 2389------------------------------------------------------------------------------
diff --git a/fs/dcache.c b/fs/dcache.c
index 43455776711e..3ee588d5f585 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1746,12 +1746,21 @@ shouldnt_be_hashed:
1746 goto shouldnt_be_hashed; 1746 goto shouldnt_be_hashed;
1747} 1747}
1748 1748
1749static int prepend(char **buffer, int *buflen, const char *str,
1750 int namelen)
1751{
1752 *buflen -= namelen;
1753 if (*buflen < 0)
1754 return -ENAMETOOLONG;
1755 *buffer -= namelen;
1756 memcpy(*buffer, str, namelen);
1757 return 0;
1758}
1759
1749/** 1760/**
1750 * d_path - return the path of a dentry 1761 * d_path - return the path of a dentry
1751 * @dentry: dentry to report 1762 * @path: the dentry/vfsmount to report
1752 * @vfsmnt: vfsmnt to which the dentry belongs 1763 * @root: root vfsmnt/dentry (may be modified by this function)
1753 * @root: root dentry
1754 * @rootmnt: vfsmnt to which the root dentry belongs
1755 * @buffer: buffer to return value in 1764 * @buffer: buffer to return value in
1756 * @buflen: buffer length 1765 * @buflen: buffer length
1757 * 1766 *
@@ -1761,23 +1770,22 @@ shouldnt_be_hashed:
1761 * Returns the buffer or an error code if the path was too long. 1770 * Returns the buffer or an error code if the path was too long.
1762 * 1771 *
1763 * "buflen" should be positive. Caller holds the dcache_lock. 1772 * "buflen" should be positive. Caller holds the dcache_lock.
1773 *
1774 * If path is not reachable from the supplied root, then the value of
1775 * root is changed (without modifying refcounts).
1764 */ 1776 */
1765static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, 1777char *__d_path(const struct path *path, struct path *root,
1766 struct path *root, char *buffer, int buflen) 1778 char *buffer, int buflen)
1767{ 1779{
1780 struct dentry *dentry = path->dentry;
1781 struct vfsmount *vfsmnt = path->mnt;
1768 char * end = buffer+buflen; 1782 char * end = buffer+buflen;
1769 char * retval; 1783 char * retval;
1770 int namelen; 1784
1771 1785 prepend(&end, &buflen, "\0", 1);
1772 *--end = '\0'; 1786 if (!IS_ROOT(dentry) && d_unhashed(dentry) &&
1773 buflen--; 1787 (prepend(&end, &buflen, " (deleted)", 10) != 0))
1774 if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
1775 buflen -= 10;
1776 end -= 10;
1777 if (buflen < 0)
1778 goto Elong; 1788 goto Elong;
1779 memcpy(end, " (deleted)", 10);
1780 }
1781 1789
1782 if (buflen < 1) 1790 if (buflen < 1)
1783 goto Elong; 1791 goto Elong;
@@ -1804,13 +1812,10 @@ static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
1804 } 1812 }
1805 parent = dentry->d_parent; 1813 parent = dentry->d_parent;
1806 prefetch(parent); 1814 prefetch(parent);
1807 namelen = dentry->d_name.len; 1815 if ((prepend(&end, &buflen, dentry->d_name.name,
1808 buflen -= namelen + 1; 1816 dentry->d_name.len) != 0) ||
1809 if (buflen < 0) 1817 (prepend(&end, &buflen, "/", 1) != 0))
1810 goto Elong; 1818 goto Elong;
1811 end -= namelen;
1812 memcpy(end, dentry->d_name.name, namelen);
1813 *--end = '/';
1814 retval = end; 1819 retval = end;
1815 dentry = parent; 1820 dentry = parent;
1816 } 1821 }
@@ -1818,12 +1823,12 @@ static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
1818 return retval; 1823 return retval;
1819 1824
1820global_root: 1825global_root:
1821 namelen = dentry->d_name.len; 1826 retval += 1; /* hit the slash */
1822 buflen -= namelen; 1827 if (prepend(&retval, &buflen, dentry->d_name.name,
1823 if (buflen < 0) 1828 dentry->d_name.len) != 0)
1824 goto Elong; 1829 goto Elong;
1825 retval -= namelen-1; /* hit the slash */ 1830 root->mnt = vfsmnt;
1826 memcpy(retval, dentry->d_name.name, namelen); 1831 root->dentry = dentry;
1827 return retval; 1832 return retval;
1828Elong: 1833Elong:
1829 return ERR_PTR(-ENAMETOOLONG); 1834 return ERR_PTR(-ENAMETOOLONG);
@@ -1846,6 +1851,7 @@ char *d_path(struct path *path, char *buf, int buflen)
1846{ 1851{
1847 char *res; 1852 char *res;
1848 struct path root; 1853 struct path root;
1854 struct path tmp;
1849 1855
1850 /* 1856 /*
1851 * We have various synthetic filesystems that never get mounted. On 1857 * We have various synthetic filesystems that never get mounted. On
@@ -1859,10 +1865,11 @@ char *d_path(struct path *path, char *buf, int buflen)
1859 1865
1860 read_lock(&current->fs->lock); 1866 read_lock(&current->fs->lock);
1861 root = current->fs->root; 1867 root = current->fs->root;
1862 path_get(&current->fs->root); 1868 path_get(&root);
1863 read_unlock(&current->fs->lock); 1869 read_unlock(&current->fs->lock);
1864 spin_lock(&dcache_lock); 1870 spin_lock(&dcache_lock);
1865 res = __d_path(path->dentry, path->mnt, &root, buf, buflen); 1871 tmp = root;
1872 res = __d_path(path, &tmp, buf, buflen);
1866 spin_unlock(&dcache_lock); 1873 spin_unlock(&dcache_lock);
1867 path_put(&root); 1874 path_put(&root);
1868 return res; 1875 return res;
@@ -1890,6 +1897,48 @@ char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen,
1890} 1897}
1891 1898
1892/* 1899/*
1900 * Write full pathname from the root of the filesystem into the buffer.
1901 */
1902char *dentry_path(struct dentry *dentry, char *buf, int buflen)
1903{
1904 char *end = buf + buflen;
1905 char *retval;
1906
1907 spin_lock(&dcache_lock);
1908 prepend(&end, &buflen, "\0", 1);
1909 if (!IS_ROOT(dentry) && d_unhashed(dentry) &&
1910 (prepend(&end, &buflen, "//deleted", 9) != 0))
1911 goto Elong;
1912 if (buflen < 1)
1913 goto Elong;
1914 /* Get '/' right */
1915 retval = end-1;
1916 *retval = '/';
1917
1918 for (;;) {
1919 struct dentry *parent;
1920 if (IS_ROOT(dentry))
1921 break;
1922
1923 parent = dentry->d_parent;
1924 prefetch(parent);
1925
1926 if ((prepend(&end, &buflen, dentry->d_name.name,
1927 dentry->d_name.len) != 0) ||
1928 (prepend(&end, &buflen, "/", 1) != 0))
1929 goto Elong;
1930
1931 retval = end;
1932 dentry = parent;
1933 }
1934 spin_unlock(&dcache_lock);
1935 return retval;
1936Elong:
1937 spin_unlock(&dcache_lock);
1938 return ERR_PTR(-ENAMETOOLONG);
1939}
1940
1941/*
1893 * NOTE! The user-level library version returns a 1942 * NOTE! The user-level library version returns a
1894 * character pointer. The kernel system call just 1943 * character pointer. The kernel system call just
1895 * returns the length of the buffer filled (which 1944 * returns the length of the buffer filled (which
@@ -1918,9 +1967,9 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
1918 1967
1919 read_lock(&current->fs->lock); 1968 read_lock(&current->fs->lock);
1920 pwd = current->fs->pwd; 1969 pwd = current->fs->pwd;
1921 path_get(&current->fs->pwd); 1970 path_get(&pwd);
1922 root = current->fs->root; 1971 root = current->fs->root;
1923 path_get(&current->fs->root); 1972 path_get(&root);
1924 read_unlock(&current->fs->lock); 1973 read_unlock(&current->fs->lock);
1925 1974
1926 error = -ENOENT; 1975 error = -ENOENT;
@@ -1928,9 +1977,10 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
1928 spin_lock(&dcache_lock); 1977 spin_lock(&dcache_lock);
1929 if (pwd.dentry->d_parent == pwd.dentry || !d_unhashed(pwd.dentry)) { 1978 if (pwd.dentry->d_parent == pwd.dentry || !d_unhashed(pwd.dentry)) {
1930 unsigned long len; 1979 unsigned long len;
1980 struct path tmp = root;
1931 char * cwd; 1981 char * cwd;
1932 1982
1933 cwd = __d_path(pwd.dentry, pwd.mnt, &root, page, PAGE_SIZE); 1983 cwd = __d_path(&pwd, &tmp, page, PAGE_SIZE);
1934 spin_unlock(&dcache_lock); 1984 spin_unlock(&dcache_lock);
1935 1985
1936 error = PTR_ERR(cwd); 1986 error = PTR_ERR(cwd);
diff --git a/fs/namespace.c b/fs/namespace.c
index 1bf302d0478b..0505fb61aa74 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -27,6 +27,7 @@
27#include <linux/mount.h> 27#include <linux/mount.h>
28#include <linux/ramfs.h> 28#include <linux/ramfs.h>
29#include <linux/log2.h> 29#include <linux/log2.h>
30#include <linux/idr.h>
30#include <asm/uaccess.h> 31#include <asm/uaccess.h>
31#include <asm/unistd.h> 32#include <asm/unistd.h>
32#include "pnode.h" 33#include "pnode.h"
@@ -39,6 +40,8 @@
39__cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); 40__cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);
40 41
41static int event; 42static int event;
43static DEFINE_IDA(mnt_id_ida);
44static DEFINE_IDA(mnt_group_ida);
42 45
43static struct list_head *mount_hashtable __read_mostly; 46static struct list_head *mount_hashtable __read_mostly;
44static struct kmem_cache *mnt_cache __read_mostly; 47static struct kmem_cache *mnt_cache __read_mostly;
@@ -58,10 +61,63 @@ static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
58 61
59#define MNT_WRITER_UNDERFLOW_LIMIT -(1<<16) 62#define MNT_WRITER_UNDERFLOW_LIMIT -(1<<16)
60 63
64/* allocation is serialized by namespace_sem */
65static int mnt_alloc_id(struct vfsmount *mnt)
66{
67 int res;
68
69retry:
70 ida_pre_get(&mnt_id_ida, GFP_KERNEL);
71 spin_lock(&vfsmount_lock);
72 res = ida_get_new(&mnt_id_ida, &mnt->mnt_id);
73 spin_unlock(&vfsmount_lock);
74 if (res == -EAGAIN)
75 goto retry;
76
77 return res;
78}
79
80static void mnt_free_id(struct vfsmount *mnt)
81{
82 spin_lock(&vfsmount_lock);
83 ida_remove(&mnt_id_ida, mnt->mnt_id);
84 spin_unlock(&vfsmount_lock);
85}
86
87/*
88 * Allocate a new peer group ID
89 *
90 * mnt_group_ida is protected by namespace_sem
91 */
92static int mnt_alloc_group_id(struct vfsmount *mnt)
93{
94 if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL))
95 return -ENOMEM;
96
97 return ida_get_new_above(&mnt_group_ida, 1, &mnt->mnt_group_id);
98}
99
100/*
101 * Release a peer group ID
102 */
103void mnt_release_group_id(struct vfsmount *mnt)
104{
105 ida_remove(&mnt_group_ida, mnt->mnt_group_id);
106 mnt->mnt_group_id = 0;
107}
108
61struct vfsmount *alloc_vfsmnt(const char *name) 109struct vfsmount *alloc_vfsmnt(const char *name)
62{ 110{
63 struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); 111 struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
64 if (mnt) { 112 if (mnt) {
113 int err;
114
115 err = mnt_alloc_id(mnt);
116 if (err) {
117 kmem_cache_free(mnt_cache, mnt);
118 return NULL;
119 }
120
65 atomic_set(&mnt->mnt_count, 1); 121 atomic_set(&mnt->mnt_count, 1);
66 INIT_LIST_HEAD(&mnt->mnt_hash); 122 INIT_LIST_HEAD(&mnt->mnt_hash);
67 INIT_LIST_HEAD(&mnt->mnt_child); 123 INIT_LIST_HEAD(&mnt->mnt_child);
@@ -353,6 +409,7 @@ EXPORT_SYMBOL(simple_set_mnt);
353void free_vfsmnt(struct vfsmount *mnt) 409void free_vfsmnt(struct vfsmount *mnt)
354{ 410{
355 kfree(mnt->mnt_devname); 411 kfree(mnt->mnt_devname);
412 mnt_free_id(mnt);
356 kmem_cache_free(mnt_cache, mnt); 413 kmem_cache_free(mnt_cache, mnt);
357} 414}
358 415
@@ -499,6 +556,17 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
499 struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname); 556 struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname);
500 557
501 if (mnt) { 558 if (mnt) {
559 if (flag & (CL_SLAVE | CL_PRIVATE))
560 mnt->mnt_group_id = 0; /* not a peer of original */
561 else
562 mnt->mnt_group_id = old->mnt_group_id;
563
564 if ((flag & CL_MAKE_SHARED) && !mnt->mnt_group_id) {
565 int err = mnt_alloc_group_id(mnt);
566 if (err)
567 goto out_free;
568 }
569
502 mnt->mnt_flags = old->mnt_flags; 570 mnt->mnt_flags = old->mnt_flags;
503 atomic_inc(&sb->s_active); 571 atomic_inc(&sb->s_active);
504 mnt->mnt_sb = sb; 572 mnt->mnt_sb = sb;
@@ -528,6 +596,10 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
528 } 596 }
529 } 597 }
530 return mnt; 598 return mnt;
599
600 out_free:
601 free_vfsmnt(mnt);
602 return NULL;
531} 603}
532 604
533static inline void __mntput(struct vfsmount *mnt) 605static inline void __mntput(struct vfsmount *mnt)
@@ -652,20 +724,21 @@ void save_mount_options(struct super_block *sb, char *options)
652} 724}
653EXPORT_SYMBOL(save_mount_options); 725EXPORT_SYMBOL(save_mount_options);
654 726
727#ifdef CONFIG_PROC_FS
655/* iterator */ 728/* iterator */
656static void *m_start(struct seq_file *m, loff_t *pos) 729static void *m_start(struct seq_file *m, loff_t *pos)
657{ 730{
658 struct mnt_namespace *n = m->private; 731 struct proc_mounts *p = m->private;
659 732
660 down_read(&namespace_sem); 733 down_read(&namespace_sem);
661 return seq_list_start(&n->list, *pos); 734 return seq_list_start(&p->ns->list, *pos);
662} 735}
663 736
664static void *m_next(struct seq_file *m, void *v, loff_t *pos) 737static void *m_next(struct seq_file *m, void *v, loff_t *pos)
665{ 738{
666 struct mnt_namespace *n = m->private; 739 struct proc_mounts *p = m->private;
667 740
668 return seq_list_next(v, &n->list, pos); 741 return seq_list_next(v, &p->ns->list, pos);
669} 742}
670 743
671static void m_stop(struct seq_file *m, void *v) 744static void m_stop(struct seq_file *m, void *v)
@@ -673,20 +746,30 @@ static void m_stop(struct seq_file *m, void *v)
673 up_read(&namespace_sem); 746 up_read(&namespace_sem);
674} 747}
675 748
676static 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)
677{ 755{
678 struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); 756 static const struct proc_fs_info fs_info[] = {
679 int err = 0;
680 static struct proc_fs_info {
681 int flag;
682 char *str;
683 } fs_info[] = {
684 { MS_SYNCHRONOUS, ",sync" }, 757 { MS_SYNCHRONOUS, ",sync" },
685 { MS_DIRSYNC, ",dirsync" }, 758 { MS_DIRSYNC, ",dirsync" },
686 { MS_MANDLOCK, ",mand" }, 759 { MS_MANDLOCK, ",mand" },
687 { 0, NULL } 760 { 0, NULL }
688 }; 761 };
689 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[] = {
690 { MNT_NOSUID, ",nosuid" }, 773 { MNT_NOSUID, ",nosuid" },
691 { MNT_NODEV, ",nodev" }, 774 { MNT_NODEV, ",nodev" },
692 { MNT_NOEXEC, ",noexec" }, 775 { MNT_NOEXEC, ",noexec" },
@@ -695,40 +778,108 @@ static int show_vfsmnt(struct seq_file *m, void *v)
695 { MNT_RELATIME, ",relatime" }, 778 { MNT_RELATIME, ",relatime" },
696 { 0, NULL } 779 { 0, NULL }
697 }; 780 };
698 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;
699 struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; 802 struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
700 803
701 mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); 804 mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
702 seq_putc(m, ' '); 805 seq_putc(m, ' ');
703 seq_path(m, &mnt_path, " \t\n\\"); 806 seq_path(m, &mnt_path, " \t\n\\");
704 seq_putc(m, ' '); 807 seq_putc(m, ' ');
705 mangle(m, mnt->mnt_sb->s_type->name); 808 show_type(m, mnt->mnt_sb);
706 if (mnt->mnt_sb->s_subtype && mnt->mnt_sb->s_subtype[0]) {
707 seq_putc(m, '.');
708 mangle(m, mnt->mnt_sb->s_subtype);
709 }
710 seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw"); 809 seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw");
711 for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { 810 show_sb_opts(m, mnt->mnt_sb);
712 if (mnt->mnt_sb->s_flags & fs_infop->flag) 811 show_mnt_opts(m, mnt);
713 seq_puts(m, fs_infop->str);
714 }
715 for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) {
716 if (mnt->mnt_flags & fs_infop->flag)
717 seq_puts(m, fs_infop->str);
718 }
719 if (mnt->mnt_sb->s_op->show_options) 812 if (mnt->mnt_sb->s_op->show_options)
720 err = mnt->mnt_sb->s_op->show_options(m, mnt); 813 err = mnt->mnt_sb->s_op->show_options(m, mnt);
721 seq_puts(m, " 0 0\n"); 814 seq_puts(m, " 0 0\n");
722 return err; 815 return err;
723} 816}
724 817
725struct seq_operations mounts_op = { 818const struct seq_operations mounts_op = {
726 .start = m_start, 819 .start = m_start,
727 .next = m_next, 820 .next = m_next,
728 .stop = m_stop, 821 .stop = m_stop,
729 .show = show_vfsmnt 822 .show = show_vfsmnt
730}; 823};
731 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 int master = mnt->mnt_master->mnt_group_id;
855 int dom = get_dominating_id(mnt, &p->root);
856 seq_printf(m, " master:%i", master);
857 if (dom && dom != master)
858 seq_printf(m, " propagate_from:%i", dom);
859 }
860 if (IS_MNT_UNBINDABLE(mnt))
861 seq_puts(m, " unbindable");
862
863 /* Filesystem specific data */
864 seq_puts(m, " - ");
865 show_type(m, sb);
866 seq_putc(m, ' ');
867 mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
868 seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw");
869 show_sb_opts(m, sb);
870 if (sb->s_op->show_options)
871 err = sb->s_op->show_options(m, mnt);
872 seq_putc(m, '\n');
873 return err;
874}
875
876const struct seq_operations mountinfo_op = {
877 .start = m_start,
878 .next = m_next,
879 .stop = m_stop,
880 .show = show_mountinfo,
881};
882
732static int show_vfsstat(struct seq_file *m, void *v) 883static int show_vfsstat(struct seq_file *m, void *v)
733{ 884{
734 struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); 885 struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list);
@@ -749,7 +900,7 @@ static int show_vfsstat(struct seq_file *m, void *v)
749 900
750 /* file system type */ 901 /* file system type */
751 seq_puts(m, "with fstype "); 902 seq_puts(m, "with fstype ");
752 mangle(m, mnt->mnt_sb->s_type->name); 903 show_type(m, mnt->mnt_sb);
753 904
754 /* optional statistics */ 905 /* optional statistics */
755 if (mnt->mnt_sb->s_op->show_stats) { 906 if (mnt->mnt_sb->s_op->show_stats) {
@@ -761,12 +912,13 @@ static int show_vfsstat(struct seq_file *m, void *v)
761 return err; 912 return err;
762} 913}
763 914
764struct seq_operations mountstats_op = { 915const struct seq_operations mountstats_op = {
765 .start = m_start, 916 .start = m_start,
766 .next = m_next, 917 .next = m_next,
767 .stop = m_stop, 918 .stop = m_stop,
768 .show = show_vfsstat, 919 .show = show_vfsstat,
769}; 920};
921#endif /* CONFIG_PROC_FS */
770 922
771/** 923/**
772 * may_umount_tree - check if a mount tree is busy 924 * may_umount_tree - check if a mount tree is busy
@@ -1108,6 +1260,33 @@ void drop_collected_mounts(struct vfsmount *mnt)
1108 release_mounts(&umount_list); 1260 release_mounts(&umount_list);
1109} 1261}
1110 1262
1263static void cleanup_group_ids(struct vfsmount *mnt, struct vfsmount *end)
1264{
1265 struct vfsmount *p;
1266
1267 for (p = mnt; p != end; p = next_mnt(p, mnt)) {
1268 if (p->mnt_group_id && !IS_MNT_SHARED(p))
1269 mnt_release_group_id(p);
1270 }
1271}
1272
1273static int invent_group_ids(struct vfsmount *mnt, bool recurse)
1274{
1275 struct vfsmount *p;
1276
1277 for (p = mnt; p; p = recurse ? next_mnt(p, mnt) : NULL) {
1278 if (!p->mnt_group_id && !IS_MNT_SHARED(p)) {
1279 int err = mnt_alloc_group_id(p);
1280 if (err) {
1281 cleanup_group_ids(mnt, p);
1282 return err;
1283 }
1284 }
1285 }
1286
1287 return 0;
1288}
1289
1111/* 1290/*
1112 * @source_mnt : mount tree to be attached 1291 * @source_mnt : mount tree to be attached
1113 * @nd : place the mount tree @source_mnt is attached 1292 * @nd : place the mount tree @source_mnt is attached
@@ -1178,9 +1357,16 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt,
1178 struct vfsmount *dest_mnt = path->mnt; 1357 struct vfsmount *dest_mnt = path->mnt;
1179 struct dentry *dest_dentry = path->dentry; 1358 struct dentry *dest_dentry = path->dentry;
1180 struct vfsmount *child, *p; 1359 struct vfsmount *child, *p;
1360 int err;
1181 1361
1182 if (propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list)) 1362 if (IS_MNT_SHARED(dest_mnt)) {
1183 return -EINVAL; 1363 err = invent_group_ids(source_mnt, true);
1364 if (err)
1365 goto out;
1366 }
1367 err = propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list);
1368 if (err)
1369 goto out_cleanup_ids;
1184 1370
1185 if (IS_MNT_SHARED(dest_mnt)) { 1371 if (IS_MNT_SHARED(dest_mnt)) {
1186 for (p = source_mnt; p; p = next_mnt(p, source_mnt)) 1372 for (p = source_mnt; p; p = next_mnt(p, source_mnt))
@@ -1203,6 +1389,12 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt,
1203 } 1389 }
1204 spin_unlock(&vfsmount_lock); 1390 spin_unlock(&vfsmount_lock);
1205 return 0; 1391 return 0;
1392
1393 out_cleanup_ids:
1394 if (IS_MNT_SHARED(dest_mnt))
1395 cleanup_group_ids(source_mnt, NULL);
1396 out:
1397 return err;
1206} 1398}
1207 1399
1208static int graft_tree(struct vfsmount *mnt, struct path *path) 1400static int graft_tree(struct vfsmount *mnt, struct path *path)
@@ -1243,6 +1435,7 @@ static noinline int do_change_type(struct nameidata *nd, int flag)
1243 struct vfsmount *m, *mnt = nd->path.mnt; 1435 struct vfsmount *m, *mnt = nd->path.mnt;
1244 int recurse = flag & MS_REC; 1436 int recurse = flag & MS_REC;
1245 int type = flag & ~MS_REC; 1437 int type = flag & ~MS_REC;
1438 int err = 0;
1246 1439
1247 if (!capable(CAP_SYS_ADMIN)) 1440 if (!capable(CAP_SYS_ADMIN))
1248 return -EPERM; 1441 return -EPERM;
@@ -1251,12 +1444,20 @@ static noinline int do_change_type(struct nameidata *nd, int flag)
1251 return -EINVAL; 1444 return -EINVAL;
1252 1445
1253 down_write(&namespace_sem); 1446 down_write(&namespace_sem);
1447 if (type == MS_SHARED) {
1448 err = invent_group_ids(mnt, recurse);
1449 if (err)
1450 goto out_unlock;
1451 }
1452
1254 spin_lock(&vfsmount_lock); 1453 spin_lock(&vfsmount_lock);
1255 for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL)) 1454 for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL))
1256 change_mnt_propagation(m, type); 1455 change_mnt_propagation(m, type);
1257 spin_unlock(&vfsmount_lock); 1456 spin_unlock(&vfsmount_lock);
1457
1458 out_unlock:
1258 up_write(&namespace_sem); 1459 up_write(&namespace_sem);
1259 return 0; 1460 return err;
1260} 1461}
1261 1462
1262/* 1463/*
diff --git a/fs/pnode.c b/fs/pnode.c
index f968e35d9785..8d5f392ec3d3 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -28,6 +28,57 @@ static inline struct vfsmount *next_slave(struct vfsmount *p)
28 return list_entry(p->mnt_slave.next, struct vfsmount, mnt_slave); 28 return list_entry(p->mnt_slave.next, struct vfsmount, mnt_slave);
29} 29}
30 30
31/*
32 * Return true if path is reachable from root
33 *
34 * namespace_sem is held, and mnt is attached
35 */
36static bool is_path_reachable(struct vfsmount *mnt, struct dentry *dentry,
37 const struct path *root)
38{
39 while (mnt != root->mnt && mnt->mnt_parent != mnt) {
40 dentry = mnt->mnt_mountpoint;
41 mnt = mnt->mnt_parent;
42 }
43 return mnt == root->mnt && is_subdir(dentry, root->dentry);
44}
45
46static struct vfsmount *get_peer_under_root(struct vfsmount *mnt,
47 struct mnt_namespace *ns,
48 const struct path *root)
49{
50 struct vfsmount *m = mnt;
51
52 do {
53 /* Check the namespace first for optimization */
54 if (m->mnt_ns == ns && is_path_reachable(m, m->mnt_root, root))
55 return m;
56
57 m = next_peer(m);
58 } while (m != mnt);
59
60 return NULL;
61}
62
63/*
64 * Get ID of closest dominating peer group having a representative
65 * under the given root.
66 *
67 * Caller must hold namespace_sem
68 */
69int get_dominating_id(struct vfsmount *mnt, const struct path *root)
70{
71 struct vfsmount *m;
72
73 for (m = mnt->mnt_master; m != NULL; m = m->mnt_master) {
74 struct vfsmount *d = get_peer_under_root(m, mnt->mnt_ns, root);
75 if (d)
76 return d->mnt_group_id;
77 }
78
79 return 0;
80}
81
31static int do_make_slave(struct vfsmount *mnt) 82static int do_make_slave(struct vfsmount *mnt)
32{ 83{
33 struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master; 84 struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master;
@@ -46,7 +97,11 @@ static int do_make_slave(struct vfsmount *mnt)
46 if (peer_mnt == mnt) 97 if (peer_mnt == mnt)
47 peer_mnt = NULL; 98 peer_mnt = NULL;
48 } 99 }
100 if (IS_MNT_SHARED(mnt) && list_empty(&mnt->mnt_share))
101 mnt_release_group_id(mnt);
102
49 list_del_init(&mnt->mnt_share); 103 list_del_init(&mnt->mnt_share);
104 mnt->mnt_group_id = 0;
50 105
51 if (peer_mnt) 106 if (peer_mnt)
52 master = peer_mnt; 107 master = peer_mnt;
@@ -68,7 +123,6 @@ static int do_make_slave(struct vfsmount *mnt)
68 } 123 }
69 mnt->mnt_master = master; 124 mnt->mnt_master = master;
70 CLEAR_MNT_SHARED(mnt); 125 CLEAR_MNT_SHARED(mnt);
71 INIT_LIST_HEAD(&mnt->mnt_slave_list);
72 return 0; 126 return 0;
73} 127}
74 128
diff --git a/fs/pnode.h b/fs/pnode.h
index 973c3f825e7d..958665d662af 100644
--- a/fs/pnode.h
+++ b/fs/pnode.h
@@ -36,4 +36,5 @@ int propagate_mnt(struct vfsmount *, struct dentry *, struct vfsmount *,
36int propagate_umount(struct list_head *); 36int propagate_umount(struct list_head *);
37int propagate_mount_busy(struct vfsmount *, int); 37int propagate_mount_busy(struct vfsmount *, int);
38void mnt_release_group_id(struct vfsmount *); 38void mnt_release_group_id(struct vfsmount *);
39int get_dominating_id(struct vfsmount *mnt, const struct path *root);
39#endif /* _LINUX_PNODE_H */ 40#endif /* _LINUX_PNODE_H */
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 7313c62e3e9d..c5e412a00b17 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -502,17 +502,14 @@ static const struct inode_operations proc_def_inode_operations = {
502 .setattr = proc_setattr, 502 .setattr = proc_setattr,
503}; 503};
504 504
505extern const struct seq_operations mounts_op; 505static int mounts_open_common(struct inode *inode, struct file *file,
506struct proc_mounts { 506 const struct seq_operations *op)
507 struct seq_file m;
508 int event;
509};
510
511static int mounts_open(struct inode *inode, struct file *file)
512{ 507{
513 struct task_struct *task = get_proc_task(inode); 508 struct task_struct *task = get_proc_task(inode);
514 struct nsproxy *nsp; 509 struct nsproxy *nsp;
515 struct mnt_namespace *ns = NULL; 510 struct mnt_namespace *ns = NULL;
511 struct fs_struct *fs = NULL;
512 struct path root;
516 struct proc_mounts *p; 513 struct proc_mounts *p;
517 int ret = -EINVAL; 514 int ret = -EINVAL;
518 515
@@ -525,40 +522,61 @@ static int mounts_open(struct inode *inode, struct file *file)
525 get_mnt_ns(ns); 522 get_mnt_ns(ns);
526 } 523 }
527 rcu_read_unlock(); 524 rcu_read_unlock();
528 525 if (ns)
526 fs = get_fs_struct(task);
529 put_task_struct(task); 527 put_task_struct(task);
530 } 528 }
531 529
532 if (ns) { 530 if (!ns)
533 ret = -ENOMEM; 531 goto err;
534 p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); 532 if (!fs)
535 if (p) { 533 goto err_put_ns;
536 file->private_data = &p->m; 534
537 ret = seq_open(file, &mounts_op); 535 read_lock(&fs->lock);
538 if (!ret) { 536 root = fs->root;
539 p->m.private = ns; 537 path_get(&root);
540 p->event = ns->event; 538 read_unlock(&fs->lock);
541 return 0; 539 put_fs_struct(fs);
542 } 540
543 kfree(p); 541 ret = -ENOMEM;
544 } 542 p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
545 put_mnt_ns(ns); 543 if (!p)
546 } 544 goto err_put_path;
545
546 file->private_data = &p->m;
547 ret = seq_open(file, op);
548 if (ret)
549 goto err_free;
550
551 p->m.private = p;
552 p->ns = ns;
553 p->root = root;
554 p->event = ns->event;
555
556 return 0;
557
558 err_free:
559 kfree(p);
560 err_put_path:
561 path_put(&root);
562 err_put_ns:
563 put_mnt_ns(ns);
564 err:
547 return ret; 565 return ret;
548} 566}
549 567
550static int mounts_release(struct inode *inode, struct file *file) 568static int mounts_release(struct inode *inode, struct file *file)
551{ 569{
552 struct seq_file *m = file->private_data; 570 struct proc_mounts *p = file->private_data;
553 struct mnt_namespace *ns = m->private; 571 path_put(&p->root);
554 put_mnt_ns(ns); 572 put_mnt_ns(p->ns);
555 return seq_release(inode, file); 573 return seq_release(inode, file);
556} 574}
557 575
558static unsigned mounts_poll(struct file *file, poll_table *wait) 576static unsigned mounts_poll(struct file *file, poll_table *wait)
559{ 577{
560 struct proc_mounts *p = file->private_data; 578 struct proc_mounts *p = file->private_data;
561 struct mnt_namespace *ns = p->m.private; 579 struct mnt_namespace *ns = p->ns;
562 unsigned res = 0; 580 unsigned res = 0;
563 581
564 poll_wait(file, &ns->poll, wait); 582 poll_wait(file, &ns->poll, wait);
@@ -573,6 +591,11 @@ static unsigned mounts_poll(struct file *file, poll_table *wait)
573 return res; 591 return res;
574} 592}
575 593
594static int mounts_open(struct inode *inode, struct file *file)
595{
596 return mounts_open_common(inode, file, &mounts_op);
597}
598
576static const struct file_operations proc_mounts_operations = { 599static const struct file_operations proc_mounts_operations = {
577 .open = mounts_open, 600 .open = mounts_open,
578 .read = seq_read, 601 .read = seq_read,
@@ -581,38 +604,22 @@ static const struct file_operations proc_mounts_operations = {
581 .poll = mounts_poll, 604 .poll = mounts_poll,
582}; 605};
583 606
584extern const struct seq_operations mountstats_op; 607static int mountinfo_open(struct inode *inode, struct file *file)
585static int mountstats_open(struct inode *inode, struct file *file)
586{ 608{
587 int ret = seq_open(file, &mountstats_op); 609 return mounts_open_common(inode, file, &mountinfo_op);
588 610}
589 if (!ret) {
590 struct seq_file *m = file->private_data;
591 struct nsproxy *nsp;
592 struct mnt_namespace *mnt_ns = NULL;
593 struct task_struct *task = get_proc_task(inode);
594
595 if (task) {
596 rcu_read_lock();
597 nsp = task_nsproxy(task);
598 if (nsp) {
599 mnt_ns = nsp->mnt_ns;
600 if (mnt_ns)
601 get_mnt_ns(mnt_ns);
602 }
603 rcu_read_unlock();
604 611
605 put_task_struct(task); 612static const struct file_operations proc_mountinfo_operations = {
606 } 613 .open = mountinfo_open,
614 .read = seq_read,
615 .llseek = seq_lseek,
616 .release = mounts_release,
617 .poll = mounts_poll,
618};
607 619
608 if (mnt_ns) 620static int mountstats_open(struct inode *inode, struct file *file)
609 m->private = mnt_ns; 621{
610 else { 622 return mounts_open_common(inode, file, &mountstats_op);
611 seq_release(inode, file);
612 ret = -EINVAL;
613 }
614 }
615 return ret;
616} 623}
617 624
618static const struct file_operations proc_mountstats_operations = { 625static const struct file_operations proc_mountstats_operations = {
@@ -2309,6 +2316,7 @@ static const struct pid_entry tgid_base_stuff[] = {
2309 LNK("root", root), 2316 LNK("root", root),
2310 LNK("exe", exe), 2317 LNK("exe", exe),
2311 REG("mounts", S_IRUGO, mounts), 2318 REG("mounts", S_IRUGO, mounts),
2319 REG("mountinfo", S_IRUGO, mountinfo),
2312 REG("mountstats", S_IRUSR, mountstats), 2320 REG("mountstats", S_IRUSR, mountstats),
2313#ifdef CONFIG_PROC_PAGE_MONITOR 2321#ifdef CONFIG_PROC_PAGE_MONITOR
2314 REG("clear_refs", S_IWUSR, clear_refs), 2322 REG("clear_refs", S_IWUSR, clear_refs),
@@ -2641,6 +2649,7 @@ static const struct pid_entry tid_base_stuff[] = {
2641 LNK("root", root), 2649 LNK("root", root),
2642 LNK("exe", exe), 2650 LNK("exe", exe),
2643 REG("mounts", S_IRUGO, mounts), 2651 REG("mounts", S_IRUGO, mounts),
2652 REG("mountinfo", S_IRUGO, mountinfo),
2644#ifdef CONFIG_PROC_PAGE_MONITOR 2653#ifdef CONFIG_PROC_PAGE_MONITOR
2645 REG("clear_refs", S_IWUSR, clear_refs), 2654 REG("clear_refs", S_IWUSR, clear_refs),
2646 REG("smaps", S_IRUGO, smaps), 2655 REG("smaps", S_IRUGO, smaps),
diff --git a/fs/seq_file.c b/fs/seq_file.c
index cdfd996ca6ef..3f54dbd6c49b 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -350,28 +350,40 @@ int seq_printf(struct seq_file *m, const char *f, ...)
350} 350}
351EXPORT_SYMBOL(seq_printf); 351EXPORT_SYMBOL(seq_printf);
352 352
353static char *mangle_path(char *s, char *p, char *esc)
354{
355 while (s <= p) {
356 char c = *p++;
357 if (!c) {
358 return s;
359 } else if (!strchr(esc, c)) {
360 *s++ = c;
361 } else if (s + 4 > p) {
362 break;
363 } else {
364 *s++ = '\\';
365 *s++ = '0' + ((c & 0300) >> 6);
366 *s++ = '0' + ((c & 070) >> 3);
367 *s++ = '0' + (c & 07);
368 }
369 }
370 return NULL;
371}
372
373/*
374 * return the absolute path of 'dentry' residing in mount 'mnt'.
375 */
353int seq_path(struct seq_file *m, struct path *path, char *esc) 376int seq_path(struct seq_file *m, struct path *path, char *esc)
354{ 377{
355 if (m->count < m->size) { 378 if (m->count < m->size) {
356 char *s = m->buf + m->count; 379 char *s = m->buf + m->count;
357 char *p = d_path(path, s, m->size - m->count); 380 char *p = d_path(path, s, m->size - m->count);
358 if (!IS_ERR(p)) { 381 if (!IS_ERR(p)) {
359 while (s <= p) { 382 s = mangle_path(s, p, esc);
360 char c = *p++; 383 if (s) {
361 if (!c) { 384 p = m->buf + m->count;
362 p = m->buf + m->count; 385 m->count = s - m->buf;
363 m->count = s - m->buf; 386 return s - p;
364 return s - p;
365 } else if (!strchr(esc, c)) {
366 *s++ = c;
367 } else if (s + 4 > p) {
368 break;
369 } else {
370 *s++ = '\\';
371 *s++ = '0' + ((c & 0300) >> 6);
372 *s++ = '0' + ((c & 070) >> 3);
373 *s++ = '0' + (c & 07);
374 }
375 } 387 }
376 } 388 }
377 } 389 }
@@ -380,6 +392,57 @@ int seq_path(struct seq_file *m, struct path *path, char *esc)
380} 392}
381EXPORT_SYMBOL(seq_path); 393EXPORT_SYMBOL(seq_path);
382 394
395/*
396 * Same as seq_path, but relative to supplied root.
397 *
398 * root may be changed, see __d_path().
399 */
400int seq_path_root(struct seq_file *m, struct path *path, struct path *root,
401 char *esc)
402{
403 int err = -ENAMETOOLONG;
404 if (m->count < m->size) {
405 char *s = m->buf + m->count;
406 char *p;
407
408 spin_lock(&dcache_lock);
409 p = __d_path(path, root, s, m->size - m->count);
410 spin_unlock(&dcache_lock);
411 err = PTR_ERR(p);
412 if (!IS_ERR(p)) {
413 s = mangle_path(s, p, esc);
414 if (s) {
415 p = m->buf + m->count;
416 m->count = s - m->buf;
417 return 0;
418 }
419 }
420 }
421 m->count = m->size;
422 return err;
423}
424
425/*
426 * returns the path of the 'dentry' from the root of its filesystem.
427 */
428int seq_dentry(struct seq_file *m, struct dentry *dentry, char *esc)
429{
430 if (m->count < m->size) {
431 char *s = m->buf + m->count;
432 char *p = dentry_path(dentry, s, m->size - m->count);
433 if (!IS_ERR(p)) {
434 s = mangle_path(s, p, esc);
435 if (s) {
436 p = m->buf + m->count;
437 m->count = s - m->buf;
438 return s - p;
439 }
440 }
441 }
442 m->count = m->size;
443 return -1;
444}
445
383static void *single_start(struct seq_file *p, loff_t *pos) 446static void *single_start(struct seq_file *p, loff_t *pos)
384{ 447{
385 return NULL + (*pos == 0); 448 return NULL + (*pos == 0);
diff --git a/fs/xattr.c b/fs/xattr.c
index f7062da505d4..89a942f07e1b 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -307,7 +307,6 @@ sys_fsetxattr(int fd, char __user *name, void __user *value,
307 error = setxattr(dentry, name, value, size, flags); 307 error = setxattr(dentry, name, value, size, flags);
308 mnt_drop_write(f->f_path.mnt); 308 mnt_drop_write(f->f_path.mnt);
309 } 309 }
310out_fput:
311 fput(f); 310 fput(f);
312 return error; 311 return error;
313} 312}
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index fabd16d03a27..cfb1627ac51c 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -301,7 +301,9 @@ extern int d_validate(struct dentry *, struct dentry *);
301 */ 301 */
302extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...); 302extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
303 303
304extern char *__d_path(const struct path *path, struct path *root, char *, int);
304extern char *d_path(struct path *, char *, int); 305extern char *d_path(struct path *, char *, int);
306extern char *dentry_path(struct dentry *, char *, int);
305 307
306/* Allocation counts.. */ 308/* Allocation counts.. */
307 309
diff --git a/include/linux/mnt_namespace.h b/include/linux/mnt_namespace.h
index 8eed44f8ca73..830bbcd449d6 100644
--- a/include/linux/mnt_namespace.h
+++ b/include/linux/mnt_namespace.h
@@ -5,6 +5,7 @@
5#include <linux/mount.h> 5#include <linux/mount.h>
6#include <linux/sched.h> 6#include <linux/sched.h>
7#include <linux/nsproxy.h> 7#include <linux/nsproxy.h>
8#include <linux/seq_file.h>
8 9
9struct mnt_namespace { 10struct mnt_namespace {
10 atomic_t count; 11 atomic_t count;
@@ -14,6 +15,13 @@ struct mnt_namespace {
14 int event; 15 int event;
15}; 16};
16 17
18struct proc_mounts {
19 struct seq_file m; /* must be the first element */
20 struct mnt_namespace *ns;
21 struct path root;
22 int event;
23};
24
17extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *, 25extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *,
18 struct fs_struct *); 26 struct fs_struct *);
19extern void __put_mnt_ns(struct mnt_namespace *ns); 27extern void __put_mnt_ns(struct mnt_namespace *ns);
@@ -37,5 +45,9 @@ static inline void get_mnt_ns(struct mnt_namespace *ns)
37 atomic_inc(&ns->count); 45 atomic_inc(&ns->count);
38} 46}
39 47
48extern const struct seq_operations mounts_op;
49extern const struct seq_operations mountinfo_op;
50extern const struct seq_operations mountstats_op;
51
40#endif 52#endif
41#endif 53#endif
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 87b24cea1863..b4836d58f428 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -56,6 +56,8 @@ struct vfsmount {
56 struct list_head mnt_slave; /* slave list entry */ 56 struct list_head mnt_slave; /* slave list entry */
57 struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */ 57 struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */
58 struct mnt_namespace *mnt_ns; /* containing namespace */ 58 struct mnt_namespace *mnt_ns; /* containing namespace */
59 int mnt_id; /* mount identifier */
60 int mnt_group_id; /* peer group identifier */
59 /* 61 /*
60 * We put mnt_count & mnt_expiry_mark at the end of struct vfsmount 62 * We put mnt_count & mnt_expiry_mark at the end of struct vfsmount
61 * to let these frequently modified fields in a separate cache line 63 * to let these frequently modified fields in a separate cache line
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index d65796dc26d9..5b5369c3c209 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -10,6 +10,7 @@ struct seq_operations;
10struct file; 10struct file;
11struct path; 11struct path;
12struct inode; 12struct inode;
13struct dentry;
13 14
14struct seq_file { 15struct seq_file {
15 char *buf; 16 char *buf;
@@ -44,6 +45,9 @@ int seq_printf(struct seq_file *, const char *, ...)
44 __attribute__ ((format (printf,2,3))); 45 __attribute__ ((format (printf,2,3)));
45 46
46int seq_path(struct seq_file *, struct path *, char *); 47int seq_path(struct seq_file *, struct path *, char *);
48int seq_dentry(struct seq_file *, struct dentry *, char *);
49int seq_path_root(struct seq_file *m, struct path *path, struct path *root,
50 char *esc);
47 51
48int single_open(struct file *, int (*)(struct seq_file *, void *), void *); 52int single_open(struct file *, int (*)(struct seq_file *, void *), void *);
49int single_release(struct inode *, struct file *); 53int single_release(struct inode *, struct file *);