Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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)

+573 -138
+38
Documentation/filesystems/proc.txt
··· 43 43 2.13 /proc/<pid>/oom_score - Display current oom-killer score 44 44 2.14 /proc/<pid>/io - Display the IO accounting fields 45 45 2.15 /proc/<pid>/coredump_filter - Core dump filtering settings 46 + 2.16 /proc/<pid>/mountinfo - Information about mounts 46 47 47 48 ------------------------------------------------------------------------------ 48 49 Preface ··· 2348 2347 2349 2348 $ echo 0x7 > /proc/self/coredump_filter 2350 2349 $ ./some_program 2350 + 2351 + 2.16 /proc/<pid>/mountinfo - Information about mounts 2352 + -------------------------------------------------------- 2353 + 2354 + This file contains lines of the form: 2355 + 2356 + 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue 2357 + (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) 2358 + 2359 + (1) mount ID: unique identifier of the mount (may be reused after umount) 2360 + (2) parent ID: ID of parent (or of self for the top of the mount tree) 2361 + (3) major:minor: value of st_dev for files on filesystem 2362 + (4) root: root of the mount within the filesystem 2363 + (5) mount point: mount point relative to the process's root 2364 + (6) mount options: per mount options 2365 + (7) optional fields: zero or more fields of the form "tag[:value]" 2366 + (8) separator: marks the end of the optional fields 2367 + (9) filesystem type: name of filesystem of the form "type[.subtype]" 2368 + (10) mount source: filesystem specific information or "none" 2369 + (11) super options: per super block options 2370 + 2371 + Parsers should ignore all unrecognised optional fields. Currently the 2372 + possible optional fields are: 2373 + 2374 + shared:X mount is shared in peer group X 2375 + master:X mount is slave to peer group X 2376 + propagate_from:X mount is slave and receives propagation from peer group X (*) 2377 + unbindable mount is unbindable 2378 + 2379 + (*) X is the closest dominant peer group under the process's root. If 2380 + X is the immediate master of the mount, or if there's no dominant peer 2381 + group under the same root, then only the "master:X" field is present 2382 + and not the "propagate_from:X" field. 2383 + 2384 + For more information on mount propagation see: 2385 + 2386 + Documentation/filesystems/sharedsubtree.txt 2351 2387 2352 2388 ------------------------------------------------------------------------------
+81 -31
fs/dcache.c
··· 1746 1746 goto shouldnt_be_hashed; 1747 1747 } 1748 1748 1749 + static 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 1761 * d_path - return the path of a dentry 1751 - * @dentry: dentry to report 1752 - * @vfsmnt: vfsmnt to which the dentry belongs 1753 - * @root: root dentry 1754 - * @rootmnt: vfsmnt to which the root dentry belongs 1762 + * @path: the dentry/vfsmount to report 1763 + * @root: root vfsmnt/dentry (may be modified by this function) 1755 1764 * @buffer: buffer to return value in 1756 1765 * @buflen: buffer length 1757 1766 * ··· 1770 1761 * Returns the buffer or an error code if the path was too long. 1771 1762 * 1772 1763 * "buflen" should be positive. Caller holds the dcache_lock. 1764 + * 1765 + * If path is not reachable from the supplied root, then the value of 1766 + * root is changed (without modifying refcounts). 1773 1767 */ 1774 - static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, 1775 - struct path *root, char *buffer, int buflen) 1768 + char *__d_path(const struct path *path, struct path *root, 1769 + char *buffer, int buflen) 1776 1770 { 1771 + struct dentry *dentry = path->dentry; 1772 + struct vfsmount *vfsmnt = path->mnt; 1777 1773 char * end = buffer+buflen; 1778 1774 char * retval; 1779 - int namelen; 1780 1775 1781 - *--end = '\0'; 1782 - buflen--; 1783 - if (!IS_ROOT(dentry) && d_unhashed(dentry)) { 1784 - buflen -= 10; 1785 - end -= 10; 1786 - if (buflen < 0) 1776 + prepend(&end, &buflen, "\0", 1); 1777 + if (!IS_ROOT(dentry) && d_unhashed(dentry) && 1778 + (prepend(&end, &buflen, " (deleted)", 10) != 0)) 1787 1779 goto Elong; 1788 - memcpy(end, " (deleted)", 10); 1789 - } 1790 1780 1791 1781 if (buflen < 1) 1792 1782 goto Elong; ··· 1812 1804 } 1813 1805 parent = dentry->d_parent; 1814 1806 prefetch(parent); 1815 - namelen = dentry->d_name.len; 1816 - buflen -= namelen + 1; 1817 - if (buflen < 0) 1807 + if ((prepend(&end, &buflen, dentry->d_name.name, 1808 + dentry->d_name.len) != 0) || 1809 + (prepend(&end, &buflen, "/", 1) != 0)) 1818 1810 goto Elong; 1819 - end -= namelen; 1820 - memcpy(end, dentry->d_name.name, namelen); 1821 - *--end = '/'; 1822 1811 retval = end; 1823 1812 dentry = parent; 1824 1813 } ··· 1823 1818 return retval; 1824 1819 1825 1820 global_root: 1826 - namelen = dentry->d_name.len; 1827 - buflen -= namelen; 1828 - if (buflen < 0) 1821 + retval += 1; /* hit the slash */ 1822 + if (prepend(&retval, &buflen, dentry->d_name.name, 1823 + dentry->d_name.len) != 0) 1829 1824 goto Elong; 1830 - retval -= namelen-1; /* hit the slash */ 1831 - memcpy(retval, dentry->d_name.name, namelen); 1825 + root->mnt = vfsmnt; 1826 + root->dentry = dentry; 1832 1827 return retval; 1833 1828 Elong: 1834 1829 return ERR_PTR(-ENAMETOOLONG); ··· 1851 1846 { 1852 1847 char *res; 1853 1848 struct path root; 1849 + struct path tmp; 1854 1850 1855 1851 /* 1856 1852 * We have various synthetic filesystems that never get mounted. On ··· 1865 1859 1866 1860 read_lock(&current->fs->lock); 1867 1861 root = current->fs->root; 1868 - path_get(&current->fs->root); 1862 + path_get(&root); 1869 1863 read_unlock(&current->fs->lock); 1870 1864 spin_lock(&dcache_lock); 1871 - res = __d_path(path->dentry, path->mnt, &root, buf, buflen); 1865 + tmp = root; 1866 + res = __d_path(path, &tmp, buf, buflen); 1872 1867 spin_unlock(&dcache_lock); 1873 1868 path_put(&root); 1874 1869 return res; ··· 1894 1887 1895 1888 buffer += buflen - sz; 1896 1889 return memcpy(buffer, temp, sz); 1890 + } 1891 + 1892 + /* 1893 + * Write full pathname from the root of the filesystem into the buffer. 1894 + */ 1895 + char *dentry_path(struct dentry *dentry, char *buf, int buflen) 1896 + { 1897 + char *end = buf + buflen; 1898 + char *retval; 1899 + 1900 + spin_lock(&dcache_lock); 1901 + prepend(&end, &buflen, "\0", 1); 1902 + if (!IS_ROOT(dentry) && d_unhashed(dentry) && 1903 + (prepend(&end, &buflen, "//deleted", 9) != 0)) 1904 + goto Elong; 1905 + if (buflen < 1) 1906 + goto Elong; 1907 + /* Get '/' right */ 1908 + retval = end-1; 1909 + *retval = '/'; 1910 + 1911 + for (;;) { 1912 + struct dentry *parent; 1913 + if (IS_ROOT(dentry)) 1914 + break; 1915 + 1916 + parent = dentry->d_parent; 1917 + prefetch(parent); 1918 + 1919 + if ((prepend(&end, &buflen, dentry->d_name.name, 1920 + dentry->d_name.len) != 0) || 1921 + (prepend(&end, &buflen, "/", 1) != 0)) 1922 + goto Elong; 1923 + 1924 + retval = end; 1925 + dentry = parent; 1926 + } 1927 + spin_unlock(&dcache_lock); 1928 + return retval; 1929 + Elong: 1930 + spin_unlock(&dcache_lock); 1931 + return ERR_PTR(-ENAMETOOLONG); 1897 1932 } 1898 1933 1899 1934 /* ··· 1967 1918 1968 1919 read_lock(&current->fs->lock); 1969 1920 pwd = current->fs->pwd; 1970 - path_get(&current->fs->pwd); 1921 + path_get(&pwd); 1971 1922 root = current->fs->root; 1972 - path_get(&current->fs->root); 1923 + path_get(&root); 1973 1924 read_unlock(&current->fs->lock); 1974 1925 1975 1926 error = -ENOENT; ··· 1977 1928 spin_lock(&dcache_lock); 1978 1929 if (pwd.dentry->d_parent == pwd.dentry || !d_unhashed(pwd.dentry)) { 1979 1930 unsigned long len; 1931 + struct path tmp = root; 1980 1932 char * cwd; 1981 1933 1982 - cwd = __d_path(pwd.dentry, pwd.mnt, &root, page, PAGE_SIZE); 1934 + cwd = __d_path(&pwd, &tmp, page, PAGE_SIZE); 1983 1935 spin_unlock(&dcache_lock); 1984 1936 1985 1937 error = PTR_ERR(cwd);
+233 -32
fs/namespace.c
··· 27 27 #include <linux/mount.h> 28 28 #include <linux/ramfs.h> 29 29 #include <linux/log2.h> 30 + #include <linux/idr.h> 30 31 #include <asm/uaccess.h> 31 32 #include <asm/unistd.h> 32 33 #include "pnode.h" ··· 40 39 __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); 41 40 42 41 static int event; 42 + static DEFINE_IDA(mnt_id_ida); 43 + static DEFINE_IDA(mnt_group_ida); 43 44 44 45 static struct list_head *mount_hashtable __read_mostly; 45 46 static struct kmem_cache *mnt_cache __read_mostly; ··· 61 58 62 59 #define MNT_WRITER_UNDERFLOW_LIMIT -(1<<16) 63 60 61 + /* allocation is serialized by namespace_sem */ 62 + static int mnt_alloc_id(struct vfsmount *mnt) 63 + { 64 + int res; 65 + 66 + retry: 67 + ida_pre_get(&mnt_id_ida, GFP_KERNEL); 68 + spin_lock(&vfsmount_lock); 69 + res = ida_get_new(&mnt_id_ida, &mnt->mnt_id); 70 + spin_unlock(&vfsmount_lock); 71 + if (res == -EAGAIN) 72 + goto retry; 73 + 74 + return res; 75 + } 76 + 77 + static void mnt_free_id(struct vfsmount *mnt) 78 + { 79 + spin_lock(&vfsmount_lock); 80 + ida_remove(&mnt_id_ida, mnt->mnt_id); 81 + spin_unlock(&vfsmount_lock); 82 + } 83 + 84 + /* 85 + * Allocate a new peer group ID 86 + * 87 + * mnt_group_ida is protected by namespace_sem 88 + */ 89 + static int mnt_alloc_group_id(struct vfsmount *mnt) 90 + { 91 + if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL)) 92 + return -ENOMEM; 93 + 94 + return ida_get_new_above(&mnt_group_ida, 1, &mnt->mnt_group_id); 95 + } 96 + 97 + /* 98 + * Release a peer group ID 99 + */ 100 + void mnt_release_group_id(struct vfsmount *mnt) 101 + { 102 + ida_remove(&mnt_group_ida, mnt->mnt_group_id); 103 + mnt->mnt_group_id = 0; 104 + } 105 + 64 106 struct vfsmount *alloc_vfsmnt(const char *name) 65 107 { 66 108 struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); 67 109 if (mnt) { 110 + int err; 111 + 112 + err = mnt_alloc_id(mnt); 113 + if (err) { 114 + kmem_cache_free(mnt_cache, mnt); 115 + return NULL; 116 + } 117 + 68 118 atomic_set(&mnt->mnt_count, 1); 69 119 INIT_LIST_HEAD(&mnt->mnt_hash); 70 120 INIT_LIST_HEAD(&mnt->mnt_child); ··· 409 353 void free_vfsmnt(struct vfsmount *mnt) 410 354 { 411 355 kfree(mnt->mnt_devname); 356 + mnt_free_id(mnt); 412 357 kmem_cache_free(mnt_cache, mnt); 413 358 } 414 359 ··· 556 499 struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname); 557 500 558 501 if (mnt) { 502 + if (flag & (CL_SLAVE | CL_PRIVATE)) 503 + mnt->mnt_group_id = 0; /* not a peer of original */ 504 + else 505 + mnt->mnt_group_id = old->mnt_group_id; 506 + 507 + if ((flag & CL_MAKE_SHARED) && !mnt->mnt_group_id) { 508 + int err = mnt_alloc_group_id(mnt); 509 + if (err) 510 + goto out_free; 511 + } 512 + 559 513 mnt->mnt_flags = old->mnt_flags; 560 514 atomic_inc(&sb->s_active); 561 515 mnt->mnt_sb = sb; ··· 596 528 } 597 529 } 598 530 return mnt; 531 + 532 + out_free: 533 + free_vfsmnt(mnt); 534 + return NULL; 599 535 } 600 536 601 537 static inline void __mntput(struct vfsmount *mnt) ··· 724 652 } 725 653 EXPORT_SYMBOL(save_mount_options); 726 654 655 + #ifdef CONFIG_PROC_FS 727 656 /* iterator */ 728 657 static void *m_start(struct seq_file *m, loff_t *pos) 729 658 { 730 - struct mnt_namespace *n = m->private; 659 + struct proc_mounts *p = m->private; 731 660 732 661 down_read(&namespace_sem); 733 - return seq_list_start(&n->list, *pos); 662 + return seq_list_start(&p->ns->list, *pos); 734 663 } 735 664 736 665 static void *m_next(struct seq_file *m, void *v, loff_t *pos) 737 666 { 738 - struct mnt_namespace *n = m->private; 667 + struct proc_mounts *p = m->private; 739 668 740 - return seq_list_next(v, &n->list, pos); 669 + return seq_list_next(v, &p->ns->list, pos); 741 670 } 742 671 743 672 static void m_stop(struct seq_file *m, void *v) ··· 746 673 up_read(&namespace_sem); 747 674 } 748 675 749 - static int show_vfsmnt(struct seq_file *m, void *v) 676 + struct proc_fs_info { 677 + int flag; 678 + const char *str; 679 + }; 680 + 681 + static void show_sb_opts(struct seq_file *m, struct super_block *sb) 750 682 { 751 - struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); 752 - int err = 0; 753 - static struct proc_fs_info { 754 - int flag; 755 - char *str; 756 - } fs_info[] = { 683 + static const struct proc_fs_info fs_info[] = { 757 684 { MS_SYNCHRONOUS, ",sync" }, 758 685 { MS_DIRSYNC, ",dirsync" }, 759 686 { MS_MANDLOCK, ",mand" }, 760 687 { 0, NULL } 761 688 }; 762 - static struct proc_fs_info mnt_info[] = { 689 + const struct proc_fs_info *fs_infop; 690 + 691 + for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { 692 + if (sb->s_flags & fs_infop->flag) 693 + seq_puts(m, fs_infop->str); 694 + } 695 + } 696 + 697 + static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt) 698 + { 699 + static const struct proc_fs_info mnt_info[] = { 763 700 { MNT_NOSUID, ",nosuid" }, 764 701 { MNT_NODEV, ",nodev" }, 765 702 { MNT_NOEXEC, ",noexec" }, ··· 778 695 { MNT_RELATIME, ",relatime" }, 779 696 { 0, NULL } 780 697 }; 781 - struct proc_fs_info *fs_infop; 698 + const struct proc_fs_info *fs_infop; 699 + 700 + for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) { 701 + if (mnt->mnt_flags & fs_infop->flag) 702 + seq_puts(m, fs_infop->str); 703 + } 704 + } 705 + 706 + static void show_type(struct seq_file *m, struct super_block *sb) 707 + { 708 + mangle(m, sb->s_type->name); 709 + if (sb->s_subtype && sb->s_subtype[0]) { 710 + seq_putc(m, '.'); 711 + mangle(m, sb->s_subtype); 712 + } 713 + } 714 + 715 + static int show_vfsmnt(struct seq_file *m, void *v) 716 + { 717 + struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); 718 + int err = 0; 782 719 struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; 783 720 784 721 mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); 785 722 seq_putc(m, ' '); 786 723 seq_path(m, &mnt_path, " \t\n\\"); 787 724 seq_putc(m, ' '); 788 - mangle(m, mnt->mnt_sb->s_type->name); 789 - if (mnt->mnt_sb->s_subtype && mnt->mnt_sb->s_subtype[0]) { 790 - seq_putc(m, '.'); 791 - mangle(m, mnt->mnt_sb->s_subtype); 792 - } 725 + show_type(m, mnt->mnt_sb); 793 726 seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw"); 794 - for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { 795 - if (mnt->mnt_sb->s_flags & fs_infop->flag) 796 - seq_puts(m, fs_infop->str); 797 - } 798 - for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) { 799 - if (mnt->mnt_flags & fs_infop->flag) 800 - seq_puts(m, fs_infop->str); 801 - } 727 + show_sb_opts(m, mnt->mnt_sb); 728 + show_mnt_opts(m, mnt); 802 729 if (mnt->mnt_sb->s_op->show_options) 803 730 err = mnt->mnt_sb->s_op->show_options(m, mnt); 804 731 seq_puts(m, " 0 0\n"); 805 732 return err; 806 733 } 807 734 808 - struct seq_operations mounts_op = { 735 + const struct seq_operations mounts_op = { 809 736 .start = m_start, 810 737 .next = m_next, 811 738 .stop = m_stop, 812 739 .show = show_vfsmnt 740 + }; 741 + 742 + static int show_mountinfo(struct seq_file *m, void *v) 743 + { 744 + struct proc_mounts *p = m->private; 745 + struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); 746 + struct super_block *sb = mnt->mnt_sb; 747 + struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; 748 + struct path root = p->root; 749 + int err = 0; 750 + 751 + seq_printf(m, "%i %i %u:%u ", mnt->mnt_id, mnt->mnt_parent->mnt_id, 752 + MAJOR(sb->s_dev), MINOR(sb->s_dev)); 753 + seq_dentry(m, mnt->mnt_root, " \t\n\\"); 754 + seq_putc(m, ' '); 755 + seq_path_root(m, &mnt_path, &root, " \t\n\\"); 756 + if (root.mnt != p->root.mnt || root.dentry != p->root.dentry) { 757 + /* 758 + * Mountpoint is outside root, discard that one. Ugly, 759 + * but less so than trying to do that in iterator in a 760 + * race-free way (due to renames). 761 + */ 762 + return SEQ_SKIP; 763 + } 764 + seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw"); 765 + show_mnt_opts(m, mnt); 766 + 767 + /* Tagged fields ("foo:X" or "bar") */ 768 + if (IS_MNT_SHARED(mnt)) 769 + seq_printf(m, " shared:%i", mnt->mnt_group_id); 770 + if (IS_MNT_SLAVE(mnt)) { 771 + int master = mnt->mnt_master->mnt_group_id; 772 + int dom = get_dominating_id(mnt, &p->root); 773 + seq_printf(m, " master:%i", master); 774 + if (dom && dom != master) 775 + seq_printf(m, " propagate_from:%i", dom); 776 + } 777 + if (IS_MNT_UNBINDABLE(mnt)) 778 + seq_puts(m, " unbindable"); 779 + 780 + /* Filesystem specific data */ 781 + seq_puts(m, " - "); 782 + show_type(m, sb); 783 + seq_putc(m, ' '); 784 + mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); 785 + seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw"); 786 + show_sb_opts(m, sb); 787 + if (sb->s_op->show_options) 788 + err = sb->s_op->show_options(m, mnt); 789 + seq_putc(m, '\n'); 790 + return err; 791 + } 792 + 793 + const struct seq_operations mountinfo_op = { 794 + .start = m_start, 795 + .next = m_next, 796 + .stop = m_stop, 797 + .show = show_mountinfo, 813 798 }; 814 799 815 800 static int show_vfsstat(struct seq_file *m, void *v) ··· 900 749 901 750 /* file system type */ 902 751 seq_puts(m, "with fstype "); 903 - mangle(m, mnt->mnt_sb->s_type->name); 752 + show_type(m, mnt->mnt_sb); 904 753 905 754 /* optional statistics */ 906 755 if (mnt->mnt_sb->s_op->show_stats) { ··· 912 761 return err; 913 762 } 914 763 915 - struct seq_operations mountstats_op = { 764 + const struct seq_operations mountstats_op = { 916 765 .start = m_start, 917 766 .next = m_next, 918 767 .stop = m_stop, 919 768 .show = show_vfsstat, 920 769 }; 770 + #endif /* CONFIG_PROC_FS */ 921 771 922 772 /** 923 773 * may_umount_tree - check if a mount tree is busy ··· 1260 1108 release_mounts(&umount_list); 1261 1109 } 1262 1110 1111 + static void cleanup_group_ids(struct vfsmount *mnt, struct vfsmount *end) 1112 + { 1113 + struct vfsmount *p; 1114 + 1115 + for (p = mnt; p != end; p = next_mnt(p, mnt)) { 1116 + if (p->mnt_group_id && !IS_MNT_SHARED(p)) 1117 + mnt_release_group_id(p); 1118 + } 1119 + } 1120 + 1121 + static int invent_group_ids(struct vfsmount *mnt, bool recurse) 1122 + { 1123 + struct vfsmount *p; 1124 + 1125 + for (p = mnt; p; p = recurse ? next_mnt(p, mnt) : NULL) { 1126 + if (!p->mnt_group_id && !IS_MNT_SHARED(p)) { 1127 + int err = mnt_alloc_group_id(p); 1128 + if (err) { 1129 + cleanup_group_ids(mnt, p); 1130 + return err; 1131 + } 1132 + } 1133 + } 1134 + 1135 + return 0; 1136 + } 1137 + 1263 1138 /* 1264 1139 * @source_mnt : mount tree to be attached 1265 1140 * @nd : place the mount tree @source_mnt is attached ··· 1357 1178 struct vfsmount *dest_mnt = path->mnt; 1358 1179 struct dentry *dest_dentry = path->dentry; 1359 1180 struct vfsmount *child, *p; 1181 + int err; 1360 1182 1361 - if (propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list)) 1362 - return -EINVAL; 1183 + if (IS_MNT_SHARED(dest_mnt)) { 1184 + err = invent_group_ids(source_mnt, true); 1185 + if (err) 1186 + goto out; 1187 + } 1188 + err = propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list); 1189 + if (err) 1190 + goto out_cleanup_ids; 1363 1191 1364 1192 if (IS_MNT_SHARED(dest_mnt)) { 1365 1193 for (p = source_mnt; p; p = next_mnt(p, source_mnt)) ··· 1389 1203 } 1390 1204 spin_unlock(&vfsmount_lock); 1391 1205 return 0; 1206 + 1207 + out_cleanup_ids: 1208 + if (IS_MNT_SHARED(dest_mnt)) 1209 + cleanup_group_ids(source_mnt, NULL); 1210 + out: 1211 + return err; 1392 1212 } 1393 1213 1394 1214 static int graft_tree(struct vfsmount *mnt, struct path *path) ··· 1435 1243 struct vfsmount *m, *mnt = nd->path.mnt; 1436 1244 int recurse = flag & MS_REC; 1437 1245 int type = flag & ~MS_REC; 1246 + int err = 0; 1438 1247 1439 1248 if (!capable(CAP_SYS_ADMIN)) 1440 1249 return -EPERM; ··· 1444 1251 return -EINVAL; 1445 1252 1446 1253 down_write(&namespace_sem); 1254 + if (type == MS_SHARED) { 1255 + err = invent_group_ids(mnt, recurse); 1256 + if (err) 1257 + goto out_unlock; 1258 + } 1259 + 1447 1260 spin_lock(&vfsmount_lock); 1448 1261 for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL)) 1449 1262 change_mnt_propagation(m, type); 1450 1263 spin_unlock(&vfsmount_lock); 1264 + 1265 + out_unlock: 1451 1266 up_write(&namespace_sem); 1452 - return 0; 1267 + return err; 1453 1268 } 1454 1269 1455 1270 /*
+55 -1
fs/pnode.c
··· 28 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 + */ 36 + static 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 + 46 + static 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 + */ 69 + int 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 + 31 82 static int do_make_slave(struct vfsmount *mnt) 32 83 { 33 84 struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master; ··· 97 46 if (peer_mnt == mnt) 98 47 peer_mnt = NULL; 99 48 } 49 + if (IS_MNT_SHARED(mnt) && list_empty(&mnt->mnt_share)) 50 + mnt_release_group_id(mnt); 51 + 100 52 list_del_init(&mnt->mnt_share); 53 + mnt->mnt_group_id = 0; 101 54 102 55 if (peer_mnt) 103 56 master = peer_mnt; ··· 123 68 } 124 69 mnt->mnt_master = master; 125 70 CLEAR_MNT_SHARED(mnt); 126 - INIT_LIST_HEAD(&mnt->mnt_slave_list); 127 71 return 0; 128 72 } 129 73
+1
fs/pnode.h
··· 36 36 int propagate_umount(struct list_head *); 37 37 int propagate_mount_busy(struct vfsmount *, int); 38 38 void mnt_release_group_id(struct vfsmount *); 39 + int get_dominating_id(struct vfsmount *mnt, const struct path *root); 39 40 #endif /* _LINUX_PNODE_H */
+66 -57
fs/proc/base.c
··· 502 502 .setattr = proc_setattr, 503 503 }; 504 504 505 - extern const struct seq_operations mounts_op; 506 - struct proc_mounts { 507 - struct seq_file m; 508 - int event; 509 - }; 510 - 511 - static int mounts_open(struct inode *inode, struct file *file) 505 + static int mounts_open_common(struct inode *inode, struct file *file, 506 + const struct seq_operations *op) 512 507 { 513 508 struct task_struct *task = get_proc_task(inode); 514 509 struct nsproxy *nsp; 515 510 struct mnt_namespace *ns = NULL; 511 + struct fs_struct *fs = NULL; 512 + struct path root; 516 513 struct proc_mounts *p; 517 514 int ret = -EINVAL; 518 515 ··· 522 525 get_mnt_ns(ns); 523 526 } 524 527 rcu_read_unlock(); 525 - 528 + if (ns) 529 + fs = get_fs_struct(task); 526 530 put_task_struct(task); 527 531 } 528 532 529 - if (ns) { 530 - ret = -ENOMEM; 531 - p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); 532 - if (p) { 533 - file->private_data = &p->m; 534 - ret = seq_open(file, &mounts_op); 535 - if (!ret) { 536 - p->m.private = ns; 537 - p->event = ns->event; 538 - return 0; 539 - } 540 - kfree(p); 541 - } 542 - put_mnt_ns(ns); 543 - } 533 + if (!ns) 534 + goto err; 535 + if (!fs) 536 + goto err_put_ns; 537 + 538 + read_lock(&fs->lock); 539 + root = fs->root; 540 + path_get(&root); 541 + read_unlock(&fs->lock); 542 + put_fs_struct(fs); 543 + 544 + ret = -ENOMEM; 545 + p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); 546 + if (!p) 547 + goto err_put_path; 548 + 549 + file->private_data = &p->m; 550 + ret = seq_open(file, op); 551 + if (ret) 552 + goto err_free; 553 + 554 + p->m.private = p; 555 + p->ns = ns; 556 + p->root = root; 557 + p->event = ns->event; 558 + 559 + return 0; 560 + 561 + err_free: 562 + kfree(p); 563 + err_put_path: 564 + path_put(&root); 565 + err_put_ns: 566 + put_mnt_ns(ns); 567 + err: 544 568 return ret; 545 569 } 546 570 547 571 static int mounts_release(struct inode *inode, struct file *file) 548 572 { 549 - struct seq_file *m = file->private_data; 550 - struct mnt_namespace *ns = m->private; 551 - put_mnt_ns(ns); 573 + struct proc_mounts *p = file->private_data; 574 + path_put(&p->root); 575 + put_mnt_ns(p->ns); 552 576 return seq_release(inode, file); 553 577 } 554 578 555 579 static unsigned mounts_poll(struct file *file, poll_table *wait) 556 580 { 557 581 struct proc_mounts *p = file->private_data; 558 - struct mnt_namespace *ns = p->m.private; 582 + struct mnt_namespace *ns = p->ns; 559 583 unsigned res = 0; 560 584 561 585 poll_wait(file, &ns->poll, wait); ··· 591 573 return res; 592 574 } 593 575 576 + static int mounts_open(struct inode *inode, struct file *file) 577 + { 578 + return mounts_open_common(inode, file, &mounts_op); 579 + } 580 + 594 581 static const struct file_operations proc_mounts_operations = { 595 582 .open = mounts_open, 596 583 .read = seq_read, ··· 604 581 .poll = mounts_poll, 605 582 }; 606 583 607 - extern const struct seq_operations mountstats_op; 584 + static int mountinfo_open(struct inode *inode, struct file *file) 585 + { 586 + return mounts_open_common(inode, file, &mountinfo_op); 587 + } 588 + 589 + static const struct file_operations proc_mountinfo_operations = { 590 + .open = mountinfo_open, 591 + .read = seq_read, 592 + .llseek = seq_lseek, 593 + .release = mounts_release, 594 + .poll = mounts_poll, 595 + }; 596 + 608 597 static int mountstats_open(struct inode *inode, struct file *file) 609 598 { 610 - int ret = seq_open(file, &mountstats_op); 611 - 612 - if (!ret) { 613 - struct seq_file *m = file->private_data; 614 - struct nsproxy *nsp; 615 - struct mnt_namespace *mnt_ns = NULL; 616 - struct task_struct *task = get_proc_task(inode); 617 - 618 - if (task) { 619 - rcu_read_lock(); 620 - nsp = task_nsproxy(task); 621 - if (nsp) { 622 - mnt_ns = nsp->mnt_ns; 623 - if (mnt_ns) 624 - get_mnt_ns(mnt_ns); 625 - } 626 - rcu_read_unlock(); 627 - 628 - put_task_struct(task); 629 - } 630 - 631 - if (mnt_ns) 632 - m->private = mnt_ns; 633 - else { 634 - seq_release(inode, file); 635 - ret = -EINVAL; 636 - } 637 - } 638 - return ret; 599 + return mounts_open_common(inode, file, &mountstats_op); 639 600 } 640 601 641 602 static const struct file_operations proc_mountstats_operations = { ··· 2316 2309 LNK("root", root), 2317 2310 LNK("exe", exe), 2318 2311 REG("mounts", S_IRUGO, mounts), 2312 + REG("mountinfo", S_IRUGO, mountinfo), 2319 2313 REG("mountstats", S_IRUSR, mountstats), 2320 2314 #ifdef CONFIG_PROC_PAGE_MONITOR 2321 2315 REG("clear_refs", S_IWUSR, clear_refs), ··· 2649 2641 LNK("root", root), 2650 2642 LNK("exe", exe), 2651 2643 REG("mounts", S_IRUGO, mounts), 2644 + REG("mountinfo", S_IRUGO, mountinfo), 2652 2645 #ifdef CONFIG_PROC_PAGE_MONITOR 2653 2646 REG("clear_refs", S_IWUSR, clear_refs), 2654 2647 REG("smaps", S_IRUGO, smaps),
+79 -16
fs/seq_file.c
··· 350 350 } 351 351 EXPORT_SYMBOL(seq_printf); 352 352 353 + static 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 + */ 353 376 int seq_path(struct seq_file *m, struct path *path, char *esc) 354 377 { 355 378 if (m->count < m->size) { 356 379 char *s = m->buf + m->count; 357 380 char *p = d_path(path, s, m->size - m->count); 358 381 if (!IS_ERR(p)) { 359 - while (s <= p) { 360 - char c = *p++; 361 - if (!c) { 362 - p = m->buf + m->count; 363 - m->count = s - m->buf; 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 - } 382 + s = mangle_path(s, p, esc); 383 + if (s) { 384 + p = m->buf + m->count; 385 + m->count = s - m->buf; 386 + return s - p; 375 387 } 376 388 } 377 389 } ··· 391 379 return -1; 392 380 } 393 381 EXPORT_SYMBOL(seq_path); 382 + 383 + /* 384 + * Same as seq_path, but relative to supplied root. 385 + * 386 + * root may be changed, see __d_path(). 387 + */ 388 + int seq_path_root(struct seq_file *m, struct path *path, struct path *root, 389 + char *esc) 390 + { 391 + int err = -ENAMETOOLONG; 392 + if (m->count < m->size) { 393 + char *s = m->buf + m->count; 394 + char *p; 395 + 396 + spin_lock(&dcache_lock); 397 + p = __d_path(path, root, s, m->size - m->count); 398 + spin_unlock(&dcache_lock); 399 + err = PTR_ERR(p); 400 + if (!IS_ERR(p)) { 401 + s = mangle_path(s, p, esc); 402 + if (s) { 403 + p = m->buf + m->count; 404 + m->count = s - m->buf; 405 + return 0; 406 + } 407 + } 408 + } 409 + m->count = m->size; 410 + return err; 411 + } 412 + 413 + /* 414 + * returns the path of the 'dentry' from the root of its filesystem. 415 + */ 416 + int seq_dentry(struct seq_file *m, struct dentry *dentry, char *esc) 417 + { 418 + if (m->count < m->size) { 419 + char *s = m->buf + m->count; 420 + char *p = dentry_path(dentry, s, m->size - m->count); 421 + if (!IS_ERR(p)) { 422 + s = mangle_path(s, p, esc); 423 + if (s) { 424 + p = m->buf + m->count; 425 + m->count = s - m->buf; 426 + return s - p; 427 + } 428 + } 429 + } 430 + m->count = m->size; 431 + return -1; 432 + } 394 433 395 434 static void *single_start(struct seq_file *p, loff_t *pos) 396 435 {
-1
fs/xattr.c
··· 307 307 error = setxattr(dentry, name, value, size, flags); 308 308 mnt_drop_write(f->f_path.mnt); 309 309 } 310 - out_fput: 311 310 fput(f); 312 311 return error; 313 312 }
+2
include/linux/dcache.h
··· 301 301 */ 302 302 extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...); 303 303 304 + extern char *__d_path(const struct path *path, struct path *root, char *, int); 304 305 extern char *d_path(struct path *, char *, int); 306 + extern char *dentry_path(struct dentry *, char *, int); 305 307 306 308 /* Allocation counts.. */ 307 309
+12
include/linux/mnt_namespace.h
··· 5 5 #include <linux/mount.h> 6 6 #include <linux/sched.h> 7 7 #include <linux/nsproxy.h> 8 + #include <linux/seq_file.h> 8 9 9 10 struct mnt_namespace { 10 11 atomic_t count; 11 12 struct vfsmount * root; 12 13 struct list_head list; 13 14 wait_queue_head_t poll; 15 + int event; 16 + }; 17 + 18 + struct proc_mounts { 19 + struct seq_file m; /* must be the first element */ 20 + struct mnt_namespace *ns; 21 + struct path root; 14 22 int event; 15 23 }; 16 24 ··· 44 36 { 45 37 atomic_inc(&ns->count); 46 38 } 39 + 40 + extern const struct seq_operations mounts_op; 41 + extern const struct seq_operations mountinfo_op; 42 + extern const struct seq_operations mountstats_op; 47 43 48 44 #endif 49 45 #endif
+2
include/linux/mount.h
··· 56 56 struct list_head mnt_slave; /* slave list entry */ 57 57 struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */ 58 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 62 * We put mnt_count & mnt_expiry_mark at the end of struct vfsmount 61 63 * to let these frequently modified fields in a separate cache line
+4
include/linux/seq_file.h
··· 10 10 struct file; 11 11 struct path; 12 12 struct inode; 13 + struct dentry; 13 14 14 15 struct seq_file { 15 16 char *buf; ··· 45 44 __attribute__ ((format (printf,2,3))); 46 45 47 46 int seq_path(struct seq_file *, struct path *, char *); 47 + int seq_dentry(struct seq_file *, struct dentry *, char *); 48 + int seq_path_root(struct seq_file *m, struct path *path, struct path *root, 49 + char *esc); 48 50 49 51 int single_open(struct file *, int (*)(struct seq_file *, void *), void *); 50 52 int single_release(struct inode *, struct file *);