diff options
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 185 |
1 files changed, 98 insertions, 87 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 7937d30a6732..5d9fd4c6d1f5 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -157,13 +157,13 @@ static void __touch_mnt_namespace(struct mnt_namespace *ns) | |||
157 | 157 | ||
158 | static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd) | 158 | static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd) |
159 | { | 159 | { |
160 | old_nd->dentry = mnt->mnt_mountpoint; | 160 | old_nd->path.dentry = mnt->mnt_mountpoint; |
161 | old_nd->mnt = mnt->mnt_parent; | 161 | old_nd->path.mnt = mnt->mnt_parent; |
162 | mnt->mnt_parent = mnt; | 162 | mnt->mnt_parent = mnt; |
163 | mnt->mnt_mountpoint = mnt->mnt_root; | 163 | mnt->mnt_mountpoint = mnt->mnt_root; |
164 | list_del_init(&mnt->mnt_child); | 164 | list_del_init(&mnt->mnt_child); |
165 | list_del_init(&mnt->mnt_hash); | 165 | list_del_init(&mnt->mnt_hash); |
166 | old_nd->dentry->d_mounted--; | 166 | old_nd->path.dentry->d_mounted--; |
167 | } | 167 | } |
168 | 168 | ||
169 | void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry, | 169 | void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry, |
@@ -176,10 +176,10 @@ void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry, | |||
176 | 176 | ||
177 | static void attach_mnt(struct vfsmount *mnt, struct nameidata *nd) | 177 | static void attach_mnt(struct vfsmount *mnt, struct nameidata *nd) |
178 | { | 178 | { |
179 | mnt_set_mountpoint(nd->mnt, nd->dentry, mnt); | 179 | mnt_set_mountpoint(nd->path.mnt, nd->path.dentry, mnt); |
180 | list_add_tail(&mnt->mnt_hash, mount_hashtable + | 180 | list_add_tail(&mnt->mnt_hash, mount_hashtable + |
181 | hash(nd->mnt, nd->dentry)); | 181 | hash(nd->path.mnt, nd->path.dentry)); |
182 | list_add_tail(&mnt->mnt_child, &nd->mnt->mnt_mounts); | 182 | list_add_tail(&mnt->mnt_child, &nd->path.mnt->mnt_mounts); |
183 | } | 183 | } |
184 | 184 | ||
185 | /* | 185 | /* |
@@ -679,20 +679,20 @@ asmlinkage long sys_umount(char __user * name, int flags) | |||
679 | if (retval) | 679 | if (retval) |
680 | goto out; | 680 | goto out; |
681 | retval = -EINVAL; | 681 | retval = -EINVAL; |
682 | if (nd.dentry != nd.mnt->mnt_root) | 682 | if (nd.path.dentry != nd.path.mnt->mnt_root) |
683 | goto dput_and_out; | 683 | goto dput_and_out; |
684 | if (!check_mnt(nd.mnt)) | 684 | if (!check_mnt(nd.path.mnt)) |
685 | goto dput_and_out; | 685 | goto dput_and_out; |
686 | 686 | ||
687 | retval = -EPERM; | 687 | retval = -EPERM; |
688 | if (!capable(CAP_SYS_ADMIN)) | 688 | if (!capable(CAP_SYS_ADMIN)) |
689 | goto dput_and_out; | 689 | goto dput_and_out; |
690 | 690 | ||
691 | retval = do_umount(nd.mnt, flags); | 691 | retval = do_umount(nd.path.mnt, flags); |
692 | dput_and_out: | 692 | dput_and_out: |
693 | /* we mustn't call path_put() as that would clear mnt_expiry_mark */ | 693 | /* we mustn't call path_put() as that would clear mnt_expiry_mark */ |
694 | dput(nd.dentry); | 694 | dput(nd.path.dentry); |
695 | mntput_no_expire(nd.mnt); | 695 | mntput_no_expire(nd.path.mnt); |
696 | out: | 696 | out: |
697 | return retval; | 697 | return retval; |
698 | } | 698 | } |
@@ -715,10 +715,10 @@ static int mount_is_safe(struct nameidata *nd) | |||
715 | return 0; | 715 | return 0; |
716 | return -EPERM; | 716 | return -EPERM; |
717 | #ifdef notyet | 717 | #ifdef notyet |
718 | if (S_ISLNK(nd->dentry->d_inode->i_mode)) | 718 | if (S_ISLNK(nd->path.dentry->d_inode->i_mode)) |
719 | return -EPERM; | 719 | return -EPERM; |
720 | if (nd->dentry->d_inode->i_mode & S_ISVTX) { | 720 | if (nd->path.dentry->d_inode->i_mode & S_ISVTX) { |
721 | if (current->uid != nd->dentry->d_inode->i_uid) | 721 | if (current->uid != nd->path.dentry->d_inode->i_uid) |
722 | return -EPERM; | 722 | return -EPERM; |
723 | } | 723 | } |
724 | if (vfs_permission(nd, MAY_WRITE)) | 724 | if (vfs_permission(nd, MAY_WRITE)) |
@@ -767,8 +767,8 @@ struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry, | |||
767 | q = q->mnt_parent; | 767 | q = q->mnt_parent; |
768 | } | 768 | } |
769 | p = s; | 769 | p = s; |
770 | nd.mnt = q; | 770 | nd.path.mnt = q; |
771 | nd.dentry = p->mnt_mountpoint; | 771 | nd.path.dentry = p->mnt_mountpoint; |
772 | q = clone_mnt(p, p->mnt_root, flag); | 772 | q = clone_mnt(p, p->mnt_root, flag); |
773 | if (!q) | 773 | if (!q) |
774 | goto Enomem; | 774 | goto Enomem; |
@@ -877,8 +877,8 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, | |||
877 | struct nameidata *nd, struct nameidata *parent_nd) | 877 | struct nameidata *nd, struct nameidata *parent_nd) |
878 | { | 878 | { |
879 | LIST_HEAD(tree_list); | 879 | LIST_HEAD(tree_list); |
880 | struct vfsmount *dest_mnt = nd->mnt; | 880 | struct vfsmount *dest_mnt = nd->path.mnt; |
881 | struct dentry *dest_dentry = nd->dentry; | 881 | struct dentry *dest_dentry = nd->path.dentry; |
882 | struct vfsmount *child, *p; | 882 | struct vfsmount *child, *p; |
883 | 883 | ||
884 | if (propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list)) | 884 | if (propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list)) |
@@ -913,13 +913,13 @@ static int graft_tree(struct vfsmount *mnt, struct nameidata *nd) | |||
913 | if (mnt->mnt_sb->s_flags & MS_NOUSER) | 913 | if (mnt->mnt_sb->s_flags & MS_NOUSER) |
914 | return -EINVAL; | 914 | return -EINVAL; |
915 | 915 | ||
916 | if (S_ISDIR(nd->dentry->d_inode->i_mode) != | 916 | if (S_ISDIR(nd->path.dentry->d_inode->i_mode) != |
917 | S_ISDIR(mnt->mnt_root->d_inode->i_mode)) | 917 | S_ISDIR(mnt->mnt_root->d_inode->i_mode)) |
918 | return -ENOTDIR; | 918 | return -ENOTDIR; |
919 | 919 | ||
920 | err = -ENOENT; | 920 | err = -ENOENT; |
921 | mutex_lock(&nd->dentry->d_inode->i_mutex); | 921 | mutex_lock(&nd->path.dentry->d_inode->i_mutex); |
922 | if (IS_DEADDIR(nd->dentry->d_inode)) | 922 | if (IS_DEADDIR(nd->path.dentry->d_inode)) |
923 | goto out_unlock; | 923 | goto out_unlock; |
924 | 924 | ||
925 | err = security_sb_check_sb(mnt, nd); | 925 | err = security_sb_check_sb(mnt, nd); |
@@ -927,10 +927,10 @@ static int graft_tree(struct vfsmount *mnt, struct nameidata *nd) | |||
927 | goto out_unlock; | 927 | goto out_unlock; |
928 | 928 | ||
929 | err = -ENOENT; | 929 | err = -ENOENT; |
930 | if (IS_ROOT(nd->dentry) || !d_unhashed(nd->dentry)) | 930 | if (IS_ROOT(nd->path.dentry) || !d_unhashed(nd->path.dentry)) |
931 | err = attach_recursive_mnt(mnt, nd, NULL); | 931 | err = attach_recursive_mnt(mnt, nd, NULL); |
932 | out_unlock: | 932 | out_unlock: |
933 | mutex_unlock(&nd->dentry->d_inode->i_mutex); | 933 | mutex_unlock(&nd->path.dentry->d_inode->i_mutex); |
934 | if (!err) | 934 | if (!err) |
935 | security_sb_post_addmount(mnt, nd); | 935 | security_sb_post_addmount(mnt, nd); |
936 | return err; | 936 | return err; |
@@ -942,14 +942,14 @@ out_unlock: | |||
942 | */ | 942 | */ |
943 | static noinline int do_change_type(struct nameidata *nd, int flag) | 943 | static noinline int do_change_type(struct nameidata *nd, int flag) |
944 | { | 944 | { |
945 | struct vfsmount *m, *mnt = nd->mnt; | 945 | struct vfsmount *m, *mnt = nd->path.mnt; |
946 | int recurse = flag & MS_REC; | 946 | int recurse = flag & MS_REC; |
947 | int type = flag & ~MS_REC; | 947 | int type = flag & ~MS_REC; |
948 | 948 | ||
949 | if (!capable(CAP_SYS_ADMIN)) | 949 | if (!capable(CAP_SYS_ADMIN)) |
950 | return -EPERM; | 950 | return -EPERM; |
951 | 951 | ||
952 | if (nd->dentry != nd->mnt->mnt_root) | 952 | if (nd->path.dentry != nd->path.mnt->mnt_root) |
953 | return -EINVAL; | 953 | return -EINVAL; |
954 | 954 | ||
955 | down_write(&namespace_sem); | 955 | down_write(&namespace_sem); |
@@ -981,17 +981,17 @@ static noinline int do_loopback(struct nameidata *nd, char *old_name, | |||
981 | 981 | ||
982 | down_write(&namespace_sem); | 982 | down_write(&namespace_sem); |
983 | err = -EINVAL; | 983 | err = -EINVAL; |
984 | if (IS_MNT_UNBINDABLE(old_nd.mnt)) | 984 | if (IS_MNT_UNBINDABLE(old_nd.path.mnt)) |
985 | goto out; | 985 | goto out; |
986 | 986 | ||
987 | if (!check_mnt(nd->mnt) || !check_mnt(old_nd.mnt)) | 987 | if (!check_mnt(nd->path.mnt) || !check_mnt(old_nd.path.mnt)) |
988 | goto out; | 988 | goto out; |
989 | 989 | ||
990 | err = -ENOMEM; | 990 | err = -ENOMEM; |
991 | if (recurse) | 991 | if (recurse) |
992 | mnt = copy_tree(old_nd.mnt, old_nd.dentry, 0); | 992 | mnt = copy_tree(old_nd.path.mnt, old_nd.path.dentry, 0); |
993 | else | 993 | else |
994 | mnt = clone_mnt(old_nd.mnt, old_nd.dentry, 0); | 994 | mnt = clone_mnt(old_nd.path.mnt, old_nd.path.dentry, 0); |
995 | 995 | ||
996 | if (!mnt) | 996 | if (!mnt) |
997 | goto out; | 997 | goto out; |
@@ -1021,24 +1021,24 @@ static noinline int do_remount(struct nameidata *nd, int flags, int mnt_flags, | |||
1021 | void *data) | 1021 | void *data) |
1022 | { | 1022 | { |
1023 | int err; | 1023 | int err; |
1024 | struct super_block *sb = nd->mnt->mnt_sb; | 1024 | struct super_block *sb = nd->path.mnt->mnt_sb; |
1025 | 1025 | ||
1026 | if (!capable(CAP_SYS_ADMIN)) | 1026 | if (!capable(CAP_SYS_ADMIN)) |
1027 | return -EPERM; | 1027 | return -EPERM; |
1028 | 1028 | ||
1029 | if (!check_mnt(nd->mnt)) | 1029 | if (!check_mnt(nd->path.mnt)) |
1030 | return -EINVAL; | 1030 | return -EINVAL; |
1031 | 1031 | ||
1032 | if (nd->dentry != nd->mnt->mnt_root) | 1032 | if (nd->path.dentry != nd->path.mnt->mnt_root) |
1033 | return -EINVAL; | 1033 | return -EINVAL; |
1034 | 1034 | ||
1035 | down_write(&sb->s_umount); | 1035 | down_write(&sb->s_umount); |
1036 | err = do_remount_sb(sb, flags, data, 0); | 1036 | err = do_remount_sb(sb, flags, data, 0); |
1037 | if (!err) | 1037 | if (!err) |
1038 | nd->mnt->mnt_flags = mnt_flags; | 1038 | nd->path.mnt->mnt_flags = mnt_flags; |
1039 | up_write(&sb->s_umount); | 1039 | up_write(&sb->s_umount); |
1040 | if (!err) | 1040 | if (!err) |
1041 | security_sb_post_remount(nd->mnt, flags, data); | 1041 | security_sb_post_remount(nd->path.mnt, flags, data); |
1042 | return err; | 1042 | return err; |
1043 | } | 1043 | } |
1044 | 1044 | ||
@@ -1069,56 +1069,60 @@ static noinline int do_move_mount(struct nameidata *nd, char *old_name) | |||
1069 | return err; | 1069 | return err; |
1070 | 1070 | ||
1071 | down_write(&namespace_sem); | 1071 | down_write(&namespace_sem); |
1072 | while (d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry)) | 1072 | while (d_mountpoint(nd->path.dentry) && |
1073 | follow_down(&nd->path.mnt, &nd->path.dentry)) | ||
1073 | ; | 1074 | ; |
1074 | err = -EINVAL; | 1075 | err = -EINVAL; |
1075 | if (!check_mnt(nd->mnt) || !check_mnt(old_nd.mnt)) | 1076 | if (!check_mnt(nd->path.mnt) || !check_mnt(old_nd.path.mnt)) |
1076 | goto out; | 1077 | goto out; |
1077 | 1078 | ||
1078 | err = -ENOENT; | 1079 | err = -ENOENT; |
1079 | mutex_lock(&nd->dentry->d_inode->i_mutex); | 1080 | mutex_lock(&nd->path.dentry->d_inode->i_mutex); |
1080 | if (IS_DEADDIR(nd->dentry->d_inode)) | 1081 | if (IS_DEADDIR(nd->path.dentry->d_inode)) |
1081 | goto out1; | 1082 | goto out1; |
1082 | 1083 | ||
1083 | if (!IS_ROOT(nd->dentry) && d_unhashed(nd->dentry)) | 1084 | if (!IS_ROOT(nd->path.dentry) && d_unhashed(nd->path.dentry)) |
1084 | goto out1; | 1085 | goto out1; |
1085 | 1086 | ||
1086 | err = -EINVAL; | 1087 | err = -EINVAL; |
1087 | if (old_nd.dentry != old_nd.mnt->mnt_root) | 1088 | if (old_nd.path.dentry != old_nd.path.mnt->mnt_root) |
1088 | goto out1; | 1089 | goto out1; |
1089 | 1090 | ||
1090 | if (old_nd.mnt == old_nd.mnt->mnt_parent) | 1091 | if (old_nd.path.mnt == old_nd.path.mnt->mnt_parent) |
1091 | goto out1; | 1092 | goto out1; |
1092 | 1093 | ||
1093 | if (S_ISDIR(nd->dentry->d_inode->i_mode) != | 1094 | if (S_ISDIR(nd->path.dentry->d_inode->i_mode) != |
1094 | S_ISDIR(old_nd.dentry->d_inode->i_mode)) | 1095 | S_ISDIR(old_nd.path.dentry->d_inode->i_mode)) |
1095 | goto out1; | 1096 | goto out1; |
1096 | /* | 1097 | /* |
1097 | * Don't move a mount residing in a shared parent. | 1098 | * Don't move a mount residing in a shared parent. |
1098 | */ | 1099 | */ |
1099 | if (old_nd.mnt->mnt_parent && IS_MNT_SHARED(old_nd.mnt->mnt_parent)) | 1100 | if (old_nd.path.mnt->mnt_parent && |
1101 | IS_MNT_SHARED(old_nd.path.mnt->mnt_parent)) | ||
1100 | goto out1; | 1102 | goto out1; |
1101 | /* | 1103 | /* |
1102 | * Don't move a mount tree containing unbindable mounts to a destination | 1104 | * Don't move a mount tree containing unbindable mounts to a destination |
1103 | * mount which is shared. | 1105 | * mount which is shared. |
1104 | */ | 1106 | */ |
1105 | if (IS_MNT_SHARED(nd->mnt) && tree_contains_unbindable(old_nd.mnt)) | 1107 | if (IS_MNT_SHARED(nd->path.mnt) && |
1108 | tree_contains_unbindable(old_nd.path.mnt)) | ||
1106 | goto out1; | 1109 | goto out1; |
1107 | err = -ELOOP; | 1110 | err = -ELOOP; |
1108 | for (p = nd->mnt; p->mnt_parent != p; p = p->mnt_parent) | 1111 | for (p = nd->path.mnt; p->mnt_parent != p; p = p->mnt_parent) |
1109 | if (p == old_nd.mnt) | 1112 | if (p == old_nd.path.mnt) |
1110 | goto out1; | 1113 | goto out1; |
1111 | 1114 | ||
1112 | if ((err = attach_recursive_mnt(old_nd.mnt, nd, &parent_nd))) | 1115 | err = attach_recursive_mnt(old_nd.path.mnt, nd, &parent_nd); |
1116 | if (err) | ||
1113 | goto out1; | 1117 | goto out1; |
1114 | 1118 | ||
1115 | spin_lock(&vfsmount_lock); | 1119 | spin_lock(&vfsmount_lock); |
1116 | /* if the mount is moved, it should no longer be expire | 1120 | /* if the mount is moved, it should no longer be expire |
1117 | * automatically */ | 1121 | * automatically */ |
1118 | list_del_init(&old_nd.mnt->mnt_expire); | 1122 | list_del_init(&old_nd.path.mnt->mnt_expire); |
1119 | spin_unlock(&vfsmount_lock); | 1123 | spin_unlock(&vfsmount_lock); |
1120 | out1: | 1124 | out1: |
1121 | mutex_unlock(&nd->dentry->d_inode->i_mutex); | 1125 | mutex_unlock(&nd->path.dentry->d_inode->i_mutex); |
1122 | out: | 1126 | out: |
1123 | up_write(&namespace_sem); | 1127 | up_write(&namespace_sem); |
1124 | if (!err) | 1128 | if (!err) |
@@ -1162,16 +1166,17 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, | |||
1162 | 1166 | ||
1163 | down_write(&namespace_sem); | 1167 | down_write(&namespace_sem); |
1164 | /* Something was mounted here while we slept */ | 1168 | /* Something was mounted here while we slept */ |
1165 | while (d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry)) | 1169 | while (d_mountpoint(nd->path.dentry) && |
1170 | follow_down(&nd->path.mnt, &nd->path.dentry)) | ||
1166 | ; | 1171 | ; |
1167 | err = -EINVAL; | 1172 | err = -EINVAL; |
1168 | if (!check_mnt(nd->mnt)) | 1173 | if (!check_mnt(nd->path.mnt)) |
1169 | goto unlock; | 1174 | goto unlock; |
1170 | 1175 | ||
1171 | /* Refuse the same filesystem on the same mount point */ | 1176 | /* Refuse the same filesystem on the same mount point */ |
1172 | err = -EBUSY; | 1177 | err = -EBUSY; |
1173 | if (nd->mnt->mnt_sb == newmnt->mnt_sb && | 1178 | if (nd->path.mnt->mnt_sb == newmnt->mnt_sb && |
1174 | nd->mnt->mnt_root == nd->dentry) | 1179 | nd->path.mnt->mnt_root == nd->path.dentry) |
1175 | goto unlock; | 1180 | goto unlock; |
1176 | 1181 | ||
1177 | err = -EINVAL; | 1182 | err = -EINVAL; |
@@ -1697,12 +1702,14 @@ static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd) | |||
1697 | if (fs) { | 1702 | if (fs) { |
1698 | atomic_inc(&fs->count); | 1703 | atomic_inc(&fs->count); |
1699 | task_unlock(p); | 1704 | task_unlock(p); |
1700 | if (fs->root == old_nd->dentry | 1705 | if (fs->root == old_nd->path.dentry |
1701 | && fs->rootmnt == old_nd->mnt) | 1706 | && fs->rootmnt == old_nd->path.mnt) |
1702 | set_fs_root(fs, new_nd->mnt, new_nd->dentry); | 1707 | set_fs_root(fs, new_nd->path.mnt, |
1703 | if (fs->pwd == old_nd->dentry | 1708 | new_nd->path.dentry); |
1704 | && fs->pwdmnt == old_nd->mnt) | 1709 | if (fs->pwd == old_nd->path.dentry |
1705 | set_fs_pwd(fs, new_nd->mnt, new_nd->dentry); | 1710 | && fs->pwdmnt == old_nd->path.mnt) |
1711 | set_fs_pwd(fs, new_nd->path.mnt, | ||
1712 | new_nd->path.dentry); | ||
1706 | put_fs_struct(fs); | 1713 | put_fs_struct(fs); |
1707 | } else | 1714 | } else |
1708 | task_unlock(p); | 1715 | task_unlock(p); |
@@ -1752,7 +1759,7 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
1752 | if (error) | 1759 | if (error) |
1753 | goto out0; | 1760 | goto out0; |
1754 | error = -EINVAL; | 1761 | error = -EINVAL; |
1755 | if (!check_mnt(new_nd.mnt)) | 1762 | if (!check_mnt(new_nd.path.mnt)) |
1756 | goto out1; | 1763 | goto out1; |
1757 | 1764 | ||
1758 | error = __user_walk(put_old, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &old_nd); | 1765 | error = __user_walk(put_old, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &old_nd); |
@@ -1766,55 +1773,59 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
1766 | } | 1773 | } |
1767 | 1774 | ||
1768 | read_lock(¤t->fs->lock); | 1775 | read_lock(¤t->fs->lock); |
1769 | user_nd.mnt = mntget(current->fs->rootmnt); | 1776 | user_nd.path.mnt = mntget(current->fs->rootmnt); |
1770 | user_nd.dentry = dget(current->fs->root); | 1777 | user_nd.path.dentry = dget(current->fs->root); |
1771 | read_unlock(¤t->fs->lock); | 1778 | read_unlock(¤t->fs->lock); |
1772 | down_write(&namespace_sem); | 1779 | down_write(&namespace_sem); |
1773 | mutex_lock(&old_nd.dentry->d_inode->i_mutex); | 1780 | mutex_lock(&old_nd.path.dentry->d_inode->i_mutex); |
1774 | error = -EINVAL; | 1781 | error = -EINVAL; |
1775 | if (IS_MNT_SHARED(old_nd.mnt) || | 1782 | if (IS_MNT_SHARED(old_nd.path.mnt) || |
1776 | IS_MNT_SHARED(new_nd.mnt->mnt_parent) || | 1783 | IS_MNT_SHARED(new_nd.path.mnt->mnt_parent) || |
1777 | IS_MNT_SHARED(user_nd.mnt->mnt_parent)) | 1784 | IS_MNT_SHARED(user_nd.path.mnt->mnt_parent)) |
1778 | goto out2; | 1785 | goto out2; |
1779 | if (!check_mnt(user_nd.mnt)) | 1786 | if (!check_mnt(user_nd.path.mnt)) |
1780 | goto out2; | 1787 | goto out2; |
1781 | error = -ENOENT; | 1788 | error = -ENOENT; |
1782 | if (IS_DEADDIR(new_nd.dentry->d_inode)) | 1789 | if (IS_DEADDIR(new_nd.path.dentry->d_inode)) |
1783 | goto out2; | 1790 | goto out2; |
1784 | if (d_unhashed(new_nd.dentry) && !IS_ROOT(new_nd.dentry)) | 1791 | if (d_unhashed(new_nd.path.dentry) && !IS_ROOT(new_nd.path.dentry)) |
1785 | goto out2; | 1792 | goto out2; |
1786 | if (d_unhashed(old_nd.dentry) && !IS_ROOT(old_nd.dentry)) | 1793 | if (d_unhashed(old_nd.path.dentry) && !IS_ROOT(old_nd.path.dentry)) |
1787 | goto out2; | 1794 | goto out2; |
1788 | error = -EBUSY; | 1795 | error = -EBUSY; |
1789 | if (new_nd.mnt == user_nd.mnt || old_nd.mnt == user_nd.mnt) | 1796 | if (new_nd.path.mnt == user_nd.path.mnt || |
1797 | old_nd.path.mnt == user_nd.path.mnt) | ||
1790 | goto out2; /* loop, on the same file system */ | 1798 | goto out2; /* loop, on the same file system */ |
1791 | error = -EINVAL; | 1799 | error = -EINVAL; |
1792 | if (user_nd.mnt->mnt_root != user_nd.dentry) | 1800 | if (user_nd.path.mnt->mnt_root != user_nd.path.dentry) |
1793 | goto out2; /* not a mountpoint */ | 1801 | goto out2; /* not a mountpoint */ |
1794 | if (user_nd.mnt->mnt_parent == user_nd.mnt) | 1802 | if (user_nd.path.mnt->mnt_parent == user_nd.path.mnt) |
1795 | goto out2; /* not attached */ | 1803 | goto out2; /* not attached */ |
1796 | if (new_nd.mnt->mnt_root != new_nd.dentry) | 1804 | if (new_nd.path.mnt->mnt_root != new_nd.path.dentry) |
1797 | goto out2; /* not a mountpoint */ | 1805 | goto out2; /* not a mountpoint */ |
1798 | if (new_nd.mnt->mnt_parent == new_nd.mnt) | 1806 | if (new_nd.path.mnt->mnt_parent == new_nd.path.mnt) |
1799 | goto out2; /* not attached */ | 1807 | goto out2; /* not attached */ |
1800 | tmp = old_nd.mnt; /* make sure we can reach put_old from new_root */ | 1808 | /* make sure we can reach put_old from new_root */ |
1809 | tmp = old_nd.path.mnt; | ||
1801 | spin_lock(&vfsmount_lock); | 1810 | spin_lock(&vfsmount_lock); |
1802 | if (tmp != new_nd.mnt) { | 1811 | if (tmp != new_nd.path.mnt) { |
1803 | for (;;) { | 1812 | for (;;) { |
1804 | if (tmp->mnt_parent == tmp) | 1813 | if (tmp->mnt_parent == tmp) |
1805 | goto out3; /* already mounted on put_old */ | 1814 | goto out3; /* already mounted on put_old */ |
1806 | if (tmp->mnt_parent == new_nd.mnt) | 1815 | if (tmp->mnt_parent == new_nd.path.mnt) |
1807 | break; | 1816 | break; |
1808 | tmp = tmp->mnt_parent; | 1817 | tmp = tmp->mnt_parent; |
1809 | } | 1818 | } |
1810 | if (!is_subdir(tmp->mnt_mountpoint, new_nd.dentry)) | 1819 | if (!is_subdir(tmp->mnt_mountpoint, new_nd.path.dentry)) |
1811 | goto out3; | 1820 | goto out3; |
1812 | } else if (!is_subdir(old_nd.dentry, new_nd.dentry)) | 1821 | } else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry)) |
1813 | goto out3; | 1822 | goto out3; |
1814 | detach_mnt(new_nd.mnt, &parent_nd); | 1823 | detach_mnt(new_nd.path.mnt, &parent_nd); |
1815 | detach_mnt(user_nd.mnt, &root_parent); | 1824 | detach_mnt(user_nd.path.mnt, &root_parent); |
1816 | attach_mnt(user_nd.mnt, &old_nd); /* mount old root on put_old */ | 1825 | /* mount old root on put_old */ |
1817 | attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */ | 1826 | attach_mnt(user_nd.path.mnt, &old_nd); |
1827 | /* mount new_root on / */ | ||
1828 | attach_mnt(new_nd.path.mnt, &root_parent); | ||
1818 | touch_mnt_namespace(current->nsproxy->mnt_ns); | 1829 | touch_mnt_namespace(current->nsproxy->mnt_ns); |
1819 | spin_unlock(&vfsmount_lock); | 1830 | spin_unlock(&vfsmount_lock); |
1820 | chroot_fs_refs(&user_nd, &new_nd); | 1831 | chroot_fs_refs(&user_nd, &new_nd); |
@@ -1823,7 +1834,7 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
1823 | path_release(&root_parent); | 1834 | path_release(&root_parent); |
1824 | path_release(&parent_nd); | 1835 | path_release(&parent_nd); |
1825 | out2: | 1836 | out2: |
1826 | mutex_unlock(&old_nd.dentry->d_inode->i_mutex); | 1837 | mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex); |
1827 | up_write(&namespace_sem); | 1838 | up_write(&namespace_sem); |
1828 | path_release(&user_nd); | 1839 | path_release(&user_nd); |
1829 | path_release(&old_nd); | 1840 | path_release(&old_nd); |