diff options
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 341 |
1 files changed, 219 insertions, 122 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 7b0b95371696..fe59bd145d21 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -196,7 +196,7 @@ unsigned int mnt_get_count(struct vfsmount *mnt) | |||
196 | #endif | 196 | #endif |
197 | } | 197 | } |
198 | 198 | ||
199 | struct vfsmount *alloc_vfsmnt(const char *name) | 199 | static struct vfsmount *alloc_vfsmnt(const char *name) |
200 | { | 200 | { |
201 | struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); | 201 | struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); |
202 | if (mnt) { | 202 | if (mnt) { |
@@ -466,15 +466,7 @@ static void __mnt_unmake_readonly(struct vfsmount *mnt) | |||
466 | br_write_unlock(vfsmount_lock); | 466 | br_write_unlock(vfsmount_lock); |
467 | } | 467 | } |
468 | 468 | ||
469 | void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb) | 469 | static void free_vfsmnt(struct vfsmount *mnt) |
470 | { | ||
471 | mnt->mnt_sb = sb; | ||
472 | mnt->mnt_root = dget(sb->s_root); | ||
473 | } | ||
474 | |||
475 | EXPORT_SYMBOL(simple_set_mnt); | ||
476 | |||
477 | void free_vfsmnt(struct vfsmount *mnt) | ||
478 | { | 470 | { |
479 | kfree(mnt->mnt_devname); | 471 | kfree(mnt->mnt_devname); |
480 | mnt_free_id(mnt); | 472 | mnt_free_id(mnt); |
@@ -678,6 +670,36 @@ static struct vfsmount *skip_mnt_tree(struct vfsmount *p) | |||
678 | return p; | 670 | return p; |
679 | } | 671 | } |
680 | 672 | ||
673 | struct vfsmount * | ||
674 | vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) | ||
675 | { | ||
676 | struct vfsmount *mnt; | ||
677 | struct dentry *root; | ||
678 | |||
679 | if (!type) | ||
680 | return ERR_PTR(-ENODEV); | ||
681 | |||
682 | mnt = alloc_vfsmnt(name); | ||
683 | if (!mnt) | ||
684 | return ERR_PTR(-ENOMEM); | ||
685 | |||
686 | if (flags & MS_KERNMOUNT) | ||
687 | mnt->mnt_flags = MNT_INTERNAL; | ||
688 | |||
689 | root = mount_fs(type, flags, name, data); | ||
690 | if (IS_ERR(root)) { | ||
691 | free_vfsmnt(mnt); | ||
692 | return ERR_CAST(root); | ||
693 | } | ||
694 | |||
695 | mnt->mnt_root = root; | ||
696 | mnt->mnt_sb = root->d_sb; | ||
697 | mnt->mnt_mountpoint = mnt->mnt_root; | ||
698 | mnt->mnt_parent = mnt; | ||
699 | return mnt; | ||
700 | } | ||
701 | EXPORT_SYMBOL_GPL(vfs_kern_mount); | ||
702 | |||
681 | static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, | 703 | static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, |
682 | int flag) | 704 | int flag) |
683 | { | 705 | { |
@@ -978,7 +1000,13 @@ static int show_vfsmnt(struct seq_file *m, void *v) | |||
978 | int err = 0; | 1000 | int err = 0; |
979 | struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; | 1001 | struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; |
980 | 1002 | ||
981 | mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); | 1003 | if (mnt->mnt_sb->s_op->show_devname) { |
1004 | err = mnt->mnt_sb->s_op->show_devname(m, mnt); | ||
1005 | if (err) | ||
1006 | goto out; | ||
1007 | } else { | ||
1008 | mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); | ||
1009 | } | ||
982 | seq_putc(m, ' '); | 1010 | seq_putc(m, ' '); |
983 | seq_path(m, &mnt_path, " \t\n\\"); | 1011 | seq_path(m, &mnt_path, " \t\n\\"); |
984 | seq_putc(m, ' '); | 1012 | seq_putc(m, ' '); |
@@ -1013,7 +1041,12 @@ static int show_mountinfo(struct seq_file *m, void *v) | |||
1013 | 1041 | ||
1014 | seq_printf(m, "%i %i %u:%u ", mnt->mnt_id, mnt->mnt_parent->mnt_id, | 1042 | seq_printf(m, "%i %i %u:%u ", mnt->mnt_id, mnt->mnt_parent->mnt_id, |
1015 | MAJOR(sb->s_dev), MINOR(sb->s_dev)); | 1043 | MAJOR(sb->s_dev), MINOR(sb->s_dev)); |
1016 | seq_dentry(m, mnt->mnt_root, " \t\n\\"); | 1044 | if (sb->s_op->show_path) |
1045 | err = sb->s_op->show_path(m, mnt); | ||
1046 | else | ||
1047 | seq_dentry(m, mnt->mnt_root, " \t\n\\"); | ||
1048 | if (err) | ||
1049 | goto out; | ||
1017 | seq_putc(m, ' '); | 1050 | seq_putc(m, ' '); |
1018 | seq_path_root(m, &mnt_path, &root, " \t\n\\"); | 1051 | seq_path_root(m, &mnt_path, &root, " \t\n\\"); |
1019 | if (root.mnt != p->root.mnt || root.dentry != p->root.dentry) { | 1052 | if (root.mnt != p->root.mnt || root.dentry != p->root.dentry) { |
@@ -1044,7 +1077,12 @@ static int show_mountinfo(struct seq_file *m, void *v) | |||
1044 | seq_puts(m, " - "); | 1077 | seq_puts(m, " - "); |
1045 | show_type(m, sb); | 1078 | show_type(m, sb); |
1046 | seq_putc(m, ' '); | 1079 | seq_putc(m, ' '); |
1047 | mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); | 1080 | if (sb->s_op->show_devname) |
1081 | err = sb->s_op->show_devname(m, mnt); | ||
1082 | else | ||
1083 | mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); | ||
1084 | if (err) | ||
1085 | goto out; | ||
1048 | seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw"); | 1086 | seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw"); |
1049 | err = show_sb_opts(m, sb); | 1087 | err = show_sb_opts(m, sb); |
1050 | if (err) | 1088 | if (err) |
@@ -1070,11 +1108,15 @@ static int show_vfsstat(struct seq_file *m, void *v) | |||
1070 | int err = 0; | 1108 | int err = 0; |
1071 | 1109 | ||
1072 | /* device */ | 1110 | /* device */ |
1073 | if (mnt->mnt_devname) { | 1111 | if (mnt->mnt_sb->s_op->show_devname) { |
1074 | seq_puts(m, "device "); | 1112 | err = mnt->mnt_sb->s_op->show_devname(m, mnt); |
1075 | mangle(m, mnt->mnt_devname); | 1113 | } else { |
1076 | } else | 1114 | if (mnt->mnt_devname) { |
1077 | seq_puts(m, "no device"); | 1115 | seq_puts(m, "device "); |
1116 | mangle(m, mnt->mnt_devname); | ||
1117 | } else | ||
1118 | seq_puts(m, "no device"); | ||
1119 | } | ||
1078 | 1120 | ||
1079 | /* mount point */ | 1121 | /* mount point */ |
1080 | seq_puts(m, " mounted on "); | 1122 | seq_puts(m, " mounted on "); |
@@ -1088,7 +1130,8 @@ static int show_vfsstat(struct seq_file *m, void *v) | |||
1088 | /* optional statistics */ | 1130 | /* optional statistics */ |
1089 | if (mnt->mnt_sb->s_op->show_stats) { | 1131 | if (mnt->mnt_sb->s_op->show_stats) { |
1090 | seq_putc(m, ' '); | 1132 | seq_putc(m, ' '); |
1091 | err = mnt->mnt_sb->s_op->show_stats(m, mnt); | 1133 | if (!err) |
1134 | err = mnt->mnt_sb->s_op->show_stats(m, mnt); | ||
1092 | } | 1135 | } |
1093 | 1136 | ||
1094 | seq_putc(m, '\n'); | 1137 | seq_putc(m, '\n'); |
@@ -1244,7 +1287,7 @@ static int do_umount(struct vfsmount *mnt, int flags) | |||
1244 | */ | 1287 | */ |
1245 | br_write_lock(vfsmount_lock); | 1288 | br_write_lock(vfsmount_lock); |
1246 | if (mnt_get_count(mnt) != 2) { | 1289 | if (mnt_get_count(mnt) != 2) { |
1247 | br_write_lock(vfsmount_lock); | 1290 | br_write_unlock(vfsmount_lock); |
1248 | return -EBUSY; | 1291 | return -EBUSY; |
1249 | } | 1292 | } |
1250 | br_write_unlock(vfsmount_lock); | 1293 | br_write_unlock(vfsmount_lock); |
@@ -1604,9 +1647,35 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, | |||
1604 | return err; | 1647 | return err; |
1605 | } | 1648 | } |
1606 | 1649 | ||
1650 | static int lock_mount(struct path *path) | ||
1651 | { | ||
1652 | struct vfsmount *mnt; | ||
1653 | retry: | ||
1654 | mutex_lock(&path->dentry->d_inode->i_mutex); | ||
1655 | if (unlikely(cant_mount(path->dentry))) { | ||
1656 | mutex_unlock(&path->dentry->d_inode->i_mutex); | ||
1657 | return -ENOENT; | ||
1658 | } | ||
1659 | down_write(&namespace_sem); | ||
1660 | mnt = lookup_mnt(path); | ||
1661 | if (likely(!mnt)) | ||
1662 | return 0; | ||
1663 | up_write(&namespace_sem); | ||
1664 | mutex_unlock(&path->dentry->d_inode->i_mutex); | ||
1665 | path_put(path); | ||
1666 | path->mnt = mnt; | ||
1667 | path->dentry = dget(mnt->mnt_root); | ||
1668 | goto retry; | ||
1669 | } | ||
1670 | |||
1671 | static void unlock_mount(struct path *path) | ||
1672 | { | ||
1673 | up_write(&namespace_sem); | ||
1674 | mutex_unlock(&path->dentry->d_inode->i_mutex); | ||
1675 | } | ||
1676 | |||
1607 | static int graft_tree(struct vfsmount *mnt, struct path *path) | 1677 | static int graft_tree(struct vfsmount *mnt, struct path *path) |
1608 | { | 1678 | { |
1609 | int err; | ||
1610 | if (mnt->mnt_sb->s_flags & MS_NOUSER) | 1679 | if (mnt->mnt_sb->s_flags & MS_NOUSER) |
1611 | return -EINVAL; | 1680 | return -EINVAL; |
1612 | 1681 | ||
@@ -1614,16 +1683,10 @@ static int graft_tree(struct vfsmount *mnt, struct path *path) | |||
1614 | S_ISDIR(mnt->mnt_root->d_inode->i_mode)) | 1683 | S_ISDIR(mnt->mnt_root->d_inode->i_mode)) |
1615 | return -ENOTDIR; | 1684 | return -ENOTDIR; |
1616 | 1685 | ||
1617 | err = -ENOENT; | 1686 | if (d_unlinked(path->dentry)) |
1618 | mutex_lock(&path->dentry->d_inode->i_mutex); | 1687 | return -ENOENT; |
1619 | if (cant_mount(path->dentry)) | ||
1620 | goto out_unlock; | ||
1621 | 1688 | ||
1622 | if (!d_unlinked(path->dentry)) | 1689 | return attach_recursive_mnt(mnt, path, NULL); |
1623 | err = attach_recursive_mnt(mnt, path, NULL); | ||
1624 | out_unlock: | ||
1625 | mutex_unlock(&path->dentry->d_inode->i_mutex); | ||
1626 | return err; | ||
1627 | } | 1690 | } |
1628 | 1691 | ||
1629 | /* | 1692 | /* |
@@ -1632,7 +1695,7 @@ out_unlock: | |||
1632 | 1695 | ||
1633 | static int flags_to_propagation_type(int flags) | 1696 | static int flags_to_propagation_type(int flags) |
1634 | { | 1697 | { |
1635 | int type = flags & ~MS_REC; | 1698 | int type = flags & ~(MS_REC | MS_SILENT); |
1636 | 1699 | ||
1637 | /* Fail if any non-propagation flags are set */ | 1700 | /* Fail if any non-propagation flags are set */ |
1638 | if (type & ~(MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) | 1701 | if (type & ~(MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) |
@@ -1686,6 +1749,7 @@ static int do_change_type(struct path *path, int flag) | |||
1686 | static int do_loopback(struct path *path, char *old_name, | 1749 | static int do_loopback(struct path *path, char *old_name, |
1687 | int recurse) | 1750 | int recurse) |
1688 | { | 1751 | { |
1752 | LIST_HEAD(umount_list); | ||
1689 | struct path old_path; | 1753 | struct path old_path; |
1690 | struct vfsmount *mnt = NULL; | 1754 | struct vfsmount *mnt = NULL; |
1691 | int err = mount_is_safe(path); | 1755 | int err = mount_is_safe(path); |
@@ -1697,13 +1761,16 @@ static int do_loopback(struct path *path, char *old_name, | |||
1697 | if (err) | 1761 | if (err) |
1698 | return err; | 1762 | return err; |
1699 | 1763 | ||
1700 | down_write(&namespace_sem); | 1764 | err = lock_mount(path); |
1765 | if (err) | ||
1766 | goto out; | ||
1767 | |||
1701 | err = -EINVAL; | 1768 | err = -EINVAL; |
1702 | if (IS_MNT_UNBINDABLE(old_path.mnt)) | 1769 | if (IS_MNT_UNBINDABLE(old_path.mnt)) |
1703 | goto out; | 1770 | goto out2; |
1704 | 1771 | ||
1705 | if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) | 1772 | if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) |
1706 | goto out; | 1773 | goto out2; |
1707 | 1774 | ||
1708 | err = -ENOMEM; | 1775 | err = -ENOMEM; |
1709 | if (recurse) | 1776 | if (recurse) |
@@ -1712,20 +1779,18 @@ static int do_loopback(struct path *path, char *old_name, | |||
1712 | mnt = clone_mnt(old_path.mnt, old_path.dentry, 0); | 1779 | mnt = clone_mnt(old_path.mnt, old_path.dentry, 0); |
1713 | 1780 | ||
1714 | if (!mnt) | 1781 | if (!mnt) |
1715 | goto out; | 1782 | goto out2; |
1716 | 1783 | ||
1717 | err = graft_tree(mnt, path); | 1784 | err = graft_tree(mnt, path); |
1718 | if (err) { | 1785 | if (err) { |
1719 | LIST_HEAD(umount_list); | ||
1720 | |||
1721 | br_write_lock(vfsmount_lock); | 1786 | br_write_lock(vfsmount_lock); |
1722 | umount_tree(mnt, 0, &umount_list); | 1787 | umount_tree(mnt, 0, &umount_list); |
1723 | br_write_unlock(vfsmount_lock); | 1788 | br_write_unlock(vfsmount_lock); |
1724 | release_mounts(&umount_list); | ||
1725 | } | 1789 | } |
1726 | 1790 | out2: | |
1791 | unlock_mount(path); | ||
1792 | release_mounts(&umount_list); | ||
1727 | out: | 1793 | out: |
1728 | up_write(&namespace_sem); | ||
1729 | path_put(&old_path); | 1794 | path_put(&old_path); |
1730 | return err; | 1795 | return err; |
1731 | } | 1796 | } |
@@ -1767,6 +1832,10 @@ static int do_remount(struct path *path, int flags, int mnt_flags, | |||
1767 | if (path->dentry != path->mnt->mnt_root) | 1832 | if (path->dentry != path->mnt->mnt_root) |
1768 | return -EINVAL; | 1833 | return -EINVAL; |
1769 | 1834 | ||
1835 | err = security_sb_remount(sb, data); | ||
1836 | if (err) | ||
1837 | return err; | ||
1838 | |||
1770 | down_write(&sb->s_umount); | 1839 | down_write(&sb->s_umount); |
1771 | if (flags & MS_BIND) | 1840 | if (flags & MS_BIND) |
1772 | err = change_mount_flags(path->mnt, flags); | 1841 | err = change_mount_flags(path->mnt, flags); |
@@ -1810,18 +1879,12 @@ static int do_move_mount(struct path *path, char *old_name) | |||
1810 | if (err) | 1879 | if (err) |
1811 | return err; | 1880 | return err; |
1812 | 1881 | ||
1813 | down_write(&namespace_sem); | 1882 | err = lock_mount(path); |
1814 | err = follow_down(path, true); | ||
1815 | if (err < 0) | 1883 | if (err < 0) |
1816 | goto out; | 1884 | goto out; |
1817 | 1885 | ||
1818 | err = -EINVAL; | 1886 | err = -EINVAL; |
1819 | if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) | 1887 | if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) |
1820 | goto out; | ||
1821 | |||
1822 | err = -ENOENT; | ||
1823 | mutex_lock(&path->dentry->d_inode->i_mutex); | ||
1824 | if (cant_mount(path->dentry)) | ||
1825 | goto out1; | 1888 | goto out1; |
1826 | 1889 | ||
1827 | if (d_unlinked(path->dentry)) | 1890 | if (d_unlinked(path->dentry)) |
@@ -1863,16 +1926,87 @@ static int do_move_mount(struct path *path, char *old_name) | |||
1863 | * automatically */ | 1926 | * automatically */ |
1864 | list_del_init(&old_path.mnt->mnt_expire); | 1927 | list_del_init(&old_path.mnt->mnt_expire); |
1865 | out1: | 1928 | out1: |
1866 | mutex_unlock(&path->dentry->d_inode->i_mutex); | 1929 | unlock_mount(path); |
1867 | out: | 1930 | out: |
1868 | up_write(&namespace_sem); | ||
1869 | if (!err) | 1931 | if (!err) |
1870 | path_put(&parent_path); | 1932 | path_put(&parent_path); |
1871 | path_put(&old_path); | 1933 | path_put(&old_path); |
1872 | return err; | 1934 | return err; |
1873 | } | 1935 | } |
1874 | 1936 | ||
1875 | static int do_add_mount(struct vfsmount *, struct path *, int); | 1937 | static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype) |
1938 | { | ||
1939 | int err; | ||
1940 | const char *subtype = strchr(fstype, '.'); | ||
1941 | if (subtype) { | ||
1942 | subtype++; | ||
1943 | err = -EINVAL; | ||
1944 | if (!subtype[0]) | ||
1945 | goto err; | ||
1946 | } else | ||
1947 | subtype = ""; | ||
1948 | |||
1949 | mnt->mnt_sb->s_subtype = kstrdup(subtype, GFP_KERNEL); | ||
1950 | err = -ENOMEM; | ||
1951 | if (!mnt->mnt_sb->s_subtype) | ||
1952 | goto err; | ||
1953 | return mnt; | ||
1954 | |||
1955 | err: | ||
1956 | mntput(mnt); | ||
1957 | return ERR_PTR(err); | ||
1958 | } | ||
1959 | |||
1960 | struct vfsmount * | ||
1961 | do_kern_mount(const char *fstype, int flags, const char *name, void *data) | ||
1962 | { | ||
1963 | struct file_system_type *type = get_fs_type(fstype); | ||
1964 | struct vfsmount *mnt; | ||
1965 | if (!type) | ||
1966 | return ERR_PTR(-ENODEV); | ||
1967 | mnt = vfs_kern_mount(type, flags, name, data); | ||
1968 | if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) && | ||
1969 | !mnt->mnt_sb->s_subtype) | ||
1970 | mnt = fs_set_subtype(mnt, fstype); | ||
1971 | put_filesystem(type); | ||
1972 | return mnt; | ||
1973 | } | ||
1974 | EXPORT_SYMBOL_GPL(do_kern_mount); | ||
1975 | |||
1976 | /* | ||
1977 | * add a mount into a namespace's mount tree | ||
1978 | */ | ||
1979 | static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags) | ||
1980 | { | ||
1981 | int err; | ||
1982 | |||
1983 | mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL); | ||
1984 | |||
1985 | err = lock_mount(path); | ||
1986 | if (err) | ||
1987 | return err; | ||
1988 | |||
1989 | err = -EINVAL; | ||
1990 | if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt)) | ||
1991 | goto unlock; | ||
1992 | |||
1993 | /* Refuse the same filesystem on the same mount point */ | ||
1994 | err = -EBUSY; | ||
1995 | if (path->mnt->mnt_sb == newmnt->mnt_sb && | ||
1996 | path->mnt->mnt_root == path->dentry) | ||
1997 | goto unlock; | ||
1998 | |||
1999 | err = -EINVAL; | ||
2000 | if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode)) | ||
2001 | goto unlock; | ||
2002 | |||
2003 | newmnt->mnt_flags = mnt_flags; | ||
2004 | err = graft_tree(newmnt, path); | ||
2005 | |||
2006 | unlock: | ||
2007 | unlock_mount(path); | ||
2008 | return err; | ||
2009 | } | ||
1876 | 2010 | ||
1877 | /* | 2011 | /* |
1878 | * create a new mount for userspace and request it to be added into the | 2012 | * create a new mount for userspace and request it to be added into the |
@@ -1932,43 +2066,6 @@ fail: | |||
1932 | return err; | 2066 | return err; |
1933 | } | 2067 | } |
1934 | 2068 | ||
1935 | /* | ||
1936 | * add a mount into a namespace's mount tree | ||
1937 | */ | ||
1938 | static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags) | ||
1939 | { | ||
1940 | int err; | ||
1941 | |||
1942 | mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL); | ||
1943 | |||
1944 | down_write(&namespace_sem); | ||
1945 | /* Something was mounted here while we slept */ | ||
1946 | err = follow_down(path, true); | ||
1947 | if (err < 0) | ||
1948 | goto unlock; | ||
1949 | |||
1950 | err = -EINVAL; | ||
1951 | if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt)) | ||
1952 | goto unlock; | ||
1953 | |||
1954 | /* Refuse the same filesystem on the same mount point */ | ||
1955 | err = -EBUSY; | ||
1956 | if (path->mnt->mnt_sb == newmnt->mnt_sb && | ||
1957 | path->mnt->mnt_root == path->dentry) | ||
1958 | goto unlock; | ||
1959 | |||
1960 | err = -EINVAL; | ||
1961 | if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode)) | ||
1962 | goto unlock; | ||
1963 | |||
1964 | newmnt->mnt_flags = mnt_flags; | ||
1965 | err = graft_tree(newmnt, path); | ||
1966 | |||
1967 | unlock: | ||
1968 | up_write(&namespace_sem); | ||
1969 | return err; | ||
1970 | } | ||
1971 | |||
1972 | /** | 2069 | /** |
1973 | * mnt_set_expiry - Put a mount on an expiration list | 2070 | * mnt_set_expiry - Put a mount on an expiration list |
1974 | * @mnt: The mount to list. | 2071 | * @mnt: The mount to list. |
@@ -2469,65 +2566,60 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, | |||
2469 | error = user_path_dir(new_root, &new); | 2566 | error = user_path_dir(new_root, &new); |
2470 | if (error) | 2567 | if (error) |
2471 | goto out0; | 2568 | goto out0; |
2472 | error = -EINVAL; | ||
2473 | if (!check_mnt(new.mnt)) | ||
2474 | goto out1; | ||
2475 | 2569 | ||
2476 | error = user_path_dir(put_old, &old); | 2570 | error = user_path_dir(put_old, &old); |
2477 | if (error) | 2571 | if (error) |
2478 | goto out1; | 2572 | goto out1; |
2479 | 2573 | ||
2480 | error = security_sb_pivotroot(&old, &new); | 2574 | error = security_sb_pivotroot(&old, &new); |
2481 | if (error) { | 2575 | if (error) |
2482 | path_put(&old); | 2576 | goto out2; |
2483 | goto out1; | ||
2484 | } | ||
2485 | 2577 | ||
2486 | get_fs_root(current->fs, &root); | 2578 | get_fs_root(current->fs, &root); |
2487 | down_write(&namespace_sem); | 2579 | error = lock_mount(&old); |
2488 | mutex_lock(&old.dentry->d_inode->i_mutex); | 2580 | if (error) |
2581 | goto out3; | ||
2582 | |||
2489 | error = -EINVAL; | 2583 | error = -EINVAL; |
2490 | if (IS_MNT_SHARED(old.mnt) || | 2584 | if (IS_MNT_SHARED(old.mnt) || |
2491 | IS_MNT_SHARED(new.mnt->mnt_parent) || | 2585 | IS_MNT_SHARED(new.mnt->mnt_parent) || |
2492 | IS_MNT_SHARED(root.mnt->mnt_parent)) | 2586 | IS_MNT_SHARED(root.mnt->mnt_parent)) |
2493 | goto out2; | 2587 | goto out4; |
2494 | if (!check_mnt(root.mnt)) | 2588 | if (!check_mnt(root.mnt) || !check_mnt(new.mnt)) |
2495 | goto out2; | 2589 | goto out4; |
2496 | error = -ENOENT; | 2590 | error = -ENOENT; |
2497 | if (cant_mount(old.dentry)) | ||
2498 | goto out2; | ||
2499 | if (d_unlinked(new.dentry)) | 2591 | if (d_unlinked(new.dentry)) |
2500 | goto out2; | 2592 | goto out4; |
2501 | if (d_unlinked(old.dentry)) | 2593 | if (d_unlinked(old.dentry)) |
2502 | goto out2; | 2594 | goto out4; |
2503 | error = -EBUSY; | 2595 | error = -EBUSY; |
2504 | if (new.mnt == root.mnt || | 2596 | if (new.mnt == root.mnt || |
2505 | old.mnt == root.mnt) | 2597 | old.mnt == root.mnt) |
2506 | goto out2; /* loop, on the same file system */ | 2598 | goto out4; /* loop, on the same file system */ |
2507 | error = -EINVAL; | 2599 | error = -EINVAL; |
2508 | if (root.mnt->mnt_root != root.dentry) | 2600 | if (root.mnt->mnt_root != root.dentry) |
2509 | goto out2; /* not a mountpoint */ | 2601 | goto out4; /* not a mountpoint */ |
2510 | if (root.mnt->mnt_parent == root.mnt) | 2602 | if (root.mnt->mnt_parent == root.mnt) |
2511 | goto out2; /* not attached */ | 2603 | goto out4; /* not attached */ |
2512 | if (new.mnt->mnt_root != new.dentry) | 2604 | if (new.mnt->mnt_root != new.dentry) |
2513 | goto out2; /* not a mountpoint */ | 2605 | goto out4; /* not a mountpoint */ |
2514 | if (new.mnt->mnt_parent == new.mnt) | 2606 | if (new.mnt->mnt_parent == new.mnt) |
2515 | goto out2; /* not attached */ | 2607 | goto out4; /* not attached */ |
2516 | /* make sure we can reach put_old from new_root */ | 2608 | /* make sure we can reach put_old from new_root */ |
2517 | tmp = old.mnt; | 2609 | tmp = old.mnt; |
2518 | br_write_lock(vfsmount_lock); | ||
2519 | if (tmp != new.mnt) { | 2610 | if (tmp != new.mnt) { |
2520 | for (;;) { | 2611 | for (;;) { |
2521 | if (tmp->mnt_parent == tmp) | 2612 | if (tmp->mnt_parent == tmp) |
2522 | goto out3; /* already mounted on put_old */ | 2613 | goto out4; /* already mounted on put_old */ |
2523 | if (tmp->mnt_parent == new.mnt) | 2614 | if (tmp->mnt_parent == new.mnt) |
2524 | break; | 2615 | break; |
2525 | tmp = tmp->mnt_parent; | 2616 | tmp = tmp->mnt_parent; |
2526 | } | 2617 | } |
2527 | if (!is_subdir(tmp->mnt_mountpoint, new.dentry)) | 2618 | if (!is_subdir(tmp->mnt_mountpoint, new.dentry)) |
2528 | goto out3; | 2619 | goto out4; |
2529 | } else if (!is_subdir(old.dentry, new.dentry)) | 2620 | } else if (!is_subdir(old.dentry, new.dentry)) |
2530 | goto out3; | 2621 | goto out4; |
2622 | br_write_lock(vfsmount_lock); | ||
2531 | detach_mnt(new.mnt, &parent_path); | 2623 | detach_mnt(new.mnt, &parent_path); |
2532 | detach_mnt(root.mnt, &root_parent); | 2624 | detach_mnt(root.mnt, &root_parent); |
2533 | /* mount old root on put_old */ | 2625 | /* mount old root on put_old */ |
@@ -2537,22 +2629,21 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, | |||
2537 | touch_mnt_namespace(current->nsproxy->mnt_ns); | 2629 | touch_mnt_namespace(current->nsproxy->mnt_ns); |
2538 | br_write_unlock(vfsmount_lock); | 2630 | br_write_unlock(vfsmount_lock); |
2539 | chroot_fs_refs(&root, &new); | 2631 | chroot_fs_refs(&root, &new); |
2540 | |||
2541 | error = 0; | 2632 | error = 0; |
2542 | path_put(&root_parent); | 2633 | out4: |
2543 | path_put(&parent_path); | 2634 | unlock_mount(&old); |
2544 | out2: | 2635 | if (!error) { |
2545 | mutex_unlock(&old.dentry->d_inode->i_mutex); | 2636 | path_put(&root_parent); |
2546 | up_write(&namespace_sem); | 2637 | path_put(&parent_path); |
2638 | } | ||
2639 | out3: | ||
2547 | path_put(&root); | 2640 | path_put(&root); |
2641 | out2: | ||
2548 | path_put(&old); | 2642 | path_put(&old); |
2549 | out1: | 2643 | out1: |
2550 | path_put(&new); | 2644 | path_put(&new); |
2551 | out0: | 2645 | out0: |
2552 | return error; | 2646 | return error; |
2553 | out3: | ||
2554 | br_write_unlock(vfsmount_lock); | ||
2555 | goto out2; | ||
2556 | } | 2647 | } |
2557 | 2648 | ||
2558 | static void __init init_mount_tree(void) | 2649 | static void __init init_mount_tree(void) |
@@ -2594,7 +2685,7 @@ void __init mnt_init(void) | |||
2594 | if (!mount_hashtable) | 2685 | if (!mount_hashtable) |
2595 | panic("Failed to allocate mount hash table\n"); | 2686 | panic("Failed to allocate mount hash table\n"); |
2596 | 2687 | ||
2597 | printk("Mount-cache hash table entries: %lu\n", HASH_SIZE); | 2688 | printk(KERN_INFO "Mount-cache hash table entries: %lu\n", HASH_SIZE); |
2598 | 2689 | ||
2599 | for (u = 0; u < HASH_SIZE; u++) | 2690 | for (u = 0; u < HASH_SIZE; u++) |
2600 | INIT_LIST_HEAD(&mount_hashtable[u]); | 2691 | INIT_LIST_HEAD(&mount_hashtable[u]); |
@@ -2627,3 +2718,9 @@ void put_mnt_ns(struct mnt_namespace *ns) | |||
2627 | kfree(ns); | 2718 | kfree(ns); |
2628 | } | 2719 | } |
2629 | EXPORT_SYMBOL(put_mnt_ns); | 2720 | EXPORT_SYMBOL(put_mnt_ns); |
2721 | |||
2722 | struct vfsmount *kern_mount_data(struct file_system_type *type, void *data) | ||
2723 | { | ||
2724 | return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data); | ||
2725 | } | ||
2726 | EXPORT_SYMBOL_GPL(kern_mount_data); | ||