diff options
| author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2008-04-19 12:17:29 -0400 |
|---|---|---|
| committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2008-04-19 12:17:29 -0400 |
| commit | adf6d34e460387ee3e8f1e1875d52bff51212c7d (patch) | |
| tree | 88ef100143e6184103a608f82dfd232bf6376eaf /fs/namespace.c | |
| parent | d1964dab60ce7c104dd21590e987a8787db18051 (diff) | |
| parent | 3760d31f11bfbd0ead9eaeb8573e0602437a9d7c (diff) | |
Merge branch 'omap2-upstream' into devel
Diffstat (limited to 'fs/namespace.c')
| -rw-r--r-- | fs/namespace.c | 200 |
1 files changed, 69 insertions, 131 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 7953c96a2071..94f026ec990a 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -155,15 +155,15 @@ static void __touch_mnt_namespace(struct mnt_namespace *ns) | |||
| 155 | } | 155 | } |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd) | 158 | static void detach_mnt(struct vfsmount *mnt, struct path *old_path) |
| 159 | { | 159 | { |
| 160 | old_nd->path.dentry = mnt->mnt_mountpoint; | 160 | old_path->dentry = mnt->mnt_mountpoint; |
| 161 | old_nd->path.mnt = mnt->mnt_parent; | 161 | old_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->path.dentry->d_mounted--; | 166 | old_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, |
| @@ -174,12 +174,12 @@ void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry, | |||
| 174 | dentry->d_mounted++; | 174 | dentry->d_mounted++; |
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | static void attach_mnt(struct vfsmount *mnt, struct nameidata *nd) | 177 | static void attach_mnt(struct vfsmount *mnt, struct path *path) |
| 178 | { | 178 | { |
| 179 | mnt_set_mountpoint(nd->path.mnt, nd->path.dentry, mnt); | 179 | mnt_set_mountpoint(path->mnt, path->dentry, mnt); |
| 180 | list_add_tail(&mnt->mnt_hash, mount_hashtable + | 180 | list_add_tail(&mnt->mnt_hash, mount_hashtable + |
| 181 | hash(nd->path.mnt, nd->path.dentry)); | 181 | hash(path->mnt, path->dentry)); |
| 182 | list_add_tail(&mnt->mnt_child, &nd->path.mnt->mnt_mounts); | 182 | list_add_tail(&mnt->mnt_child, &path->mnt->mnt_mounts); |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | /* | 185 | /* |
| @@ -262,10 +262,8 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, | |||
| 262 | /* stick the duplicate mount on the same expiry list | 262 | /* stick the duplicate mount on the same expiry list |
| 263 | * as the original if that was on one */ | 263 | * as the original if that was on one */ |
| 264 | if (flag & CL_EXPIRE) { | 264 | if (flag & CL_EXPIRE) { |
| 265 | spin_lock(&vfsmount_lock); | ||
| 266 | if (!list_empty(&old->mnt_expire)) | 265 | if (!list_empty(&old->mnt_expire)) |
| 267 | list_add(&mnt->mnt_expire, &old->mnt_expire); | 266 | list_add(&mnt->mnt_expire, &old->mnt_expire); |
| 268 | spin_unlock(&vfsmount_lock); | ||
| 269 | } | 267 | } |
| 270 | } | 268 | } |
| 271 | return mnt; | 269 | return mnt; |
| @@ -548,6 +546,7 @@ void release_mounts(struct list_head *head) | |||
| 548 | m = mnt->mnt_parent; | 546 | m = mnt->mnt_parent; |
| 549 | mnt->mnt_mountpoint = mnt->mnt_root; | 547 | mnt->mnt_mountpoint = mnt->mnt_root; |
| 550 | mnt->mnt_parent = mnt; | 548 | mnt->mnt_parent = mnt; |
| 549 | m->mnt_ghosts--; | ||
| 551 | spin_unlock(&vfsmount_lock); | 550 | spin_unlock(&vfsmount_lock); |
| 552 | dput(dentry); | 551 | dput(dentry); |
| 553 | mntput(m); | 552 | mntput(m); |
| @@ -572,12 +571,16 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) | |||
| 572 | __touch_mnt_namespace(p->mnt_ns); | 571 | __touch_mnt_namespace(p->mnt_ns); |
| 573 | p->mnt_ns = NULL; | 572 | p->mnt_ns = NULL; |
| 574 | list_del_init(&p->mnt_child); | 573 | list_del_init(&p->mnt_child); |
| 575 | if (p->mnt_parent != p) | 574 | if (p->mnt_parent != p) { |
| 575 | p->mnt_parent->mnt_ghosts++; | ||
| 576 | p->mnt_mountpoint->d_mounted--; | 576 | p->mnt_mountpoint->d_mounted--; |
| 577 | } | ||
| 577 | change_mnt_propagation(p, MS_PRIVATE); | 578 | change_mnt_propagation(p, MS_PRIVATE); |
| 578 | } | 579 | } |
| 579 | } | 580 | } |
| 580 | 581 | ||
| 582 | static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts); | ||
| 583 | |||
| 581 | static int do_umount(struct vfsmount *mnt, int flags) | 584 | static int do_umount(struct vfsmount *mnt, int flags) |
| 582 | { | 585 | { |
| 583 | struct super_block *sb = mnt->mnt_sb; | 586 | struct super_block *sb = mnt->mnt_sb; |
| @@ -650,6 +653,9 @@ static int do_umount(struct vfsmount *mnt, int flags) | |||
| 650 | spin_lock(&vfsmount_lock); | 653 | spin_lock(&vfsmount_lock); |
| 651 | event++; | 654 | event++; |
| 652 | 655 | ||
| 656 | if (!(flags & MNT_DETACH)) | ||
| 657 | shrink_submounts(mnt, &umount_list); | ||
| 658 | |||
| 653 | retval = -EBUSY; | 659 | retval = -EBUSY; |
| 654 | if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) { | 660 | if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) { |
| 655 | if (!list_empty(&mnt->mnt_list)) | 661 | if (!list_empty(&mnt->mnt_list)) |
| @@ -744,7 +750,7 @@ struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry, | |||
| 744 | int flag) | 750 | int flag) |
| 745 | { | 751 | { |
| 746 | struct vfsmount *res, *p, *q, *r, *s; | 752 | struct vfsmount *res, *p, *q, *r, *s; |
| 747 | struct nameidata nd; | 753 | struct path path; |
| 748 | 754 | ||
| 749 | if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt)) | 755 | if (!(flag & CL_COPY_ALL) && IS_MNT_UNBINDABLE(mnt)) |
| 750 | return NULL; | 756 | return NULL; |
| @@ -769,14 +775,14 @@ struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry, | |||
| 769 | q = q->mnt_parent; | 775 | q = q->mnt_parent; |
| 770 | } | 776 | } |
| 771 | p = s; | 777 | p = s; |
| 772 | nd.path.mnt = q; | 778 | path.mnt = q; |
| 773 | nd.path.dentry = p->mnt_mountpoint; | 779 | path.dentry = p->mnt_mountpoint; |
| 774 | q = clone_mnt(p, p->mnt_root, flag); | 780 | q = clone_mnt(p, p->mnt_root, flag); |
| 775 | if (!q) | 781 | if (!q) |
| 776 | goto Enomem; | 782 | goto Enomem; |
| 777 | spin_lock(&vfsmount_lock); | 783 | spin_lock(&vfsmount_lock); |
| 778 | list_add_tail(&q->mnt_list, &res->mnt_list); | 784 | list_add_tail(&q->mnt_list, &res->mnt_list); |
| 779 | attach_mnt(q, &nd); | 785 | attach_mnt(q, &path); |
| 780 | spin_unlock(&vfsmount_lock); | 786 | spin_unlock(&vfsmount_lock); |
| 781 | } | 787 | } |
| 782 | } | 788 | } |
| @@ -876,11 +882,11 @@ void drop_collected_mounts(struct vfsmount *mnt) | |||
| 876 | * in allocations. | 882 | * in allocations. |
| 877 | */ | 883 | */ |
| 878 | static int attach_recursive_mnt(struct vfsmount *source_mnt, | 884 | static int attach_recursive_mnt(struct vfsmount *source_mnt, |
| 879 | struct nameidata *nd, struct nameidata *parent_nd) | 885 | struct path *path, struct path *parent_path) |
| 880 | { | 886 | { |
| 881 | LIST_HEAD(tree_list); | 887 | LIST_HEAD(tree_list); |
| 882 | struct vfsmount *dest_mnt = nd->path.mnt; | 888 | struct vfsmount *dest_mnt = path->mnt; |
| 883 | struct dentry *dest_dentry = nd->path.dentry; | 889 | struct dentry *dest_dentry = path->dentry; |
| 884 | struct vfsmount *child, *p; | 890 | struct vfsmount *child, *p; |
| 885 | 891 | ||
| 886 | if (propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list)) | 892 | if (propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list)) |
| @@ -892,9 +898,9 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, | |||
| 892 | } | 898 | } |
| 893 | 899 | ||
| 894 | spin_lock(&vfsmount_lock); | 900 | spin_lock(&vfsmount_lock); |
| 895 | if (parent_nd) { | 901 | if (parent_path) { |
| 896 | detach_mnt(source_mnt, parent_nd); | 902 | detach_mnt(source_mnt, parent_path); |
| 897 | attach_mnt(source_mnt, nd); | 903 | attach_mnt(source_mnt, path); |
| 898 | touch_mnt_namespace(current->nsproxy->mnt_ns); | 904 | touch_mnt_namespace(current->nsproxy->mnt_ns); |
| 899 | } else { | 905 | } else { |
| 900 | mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt); | 906 | mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt); |
| @@ -930,7 +936,7 @@ static int graft_tree(struct vfsmount *mnt, struct nameidata *nd) | |||
| 930 | 936 | ||
| 931 | err = -ENOENT; | 937 | err = -ENOENT; |
| 932 | if (IS_ROOT(nd->path.dentry) || !d_unhashed(nd->path.dentry)) | 938 | if (IS_ROOT(nd->path.dentry) || !d_unhashed(nd->path.dentry)) |
| 933 | err = attach_recursive_mnt(mnt, nd, NULL); | 939 | err = attach_recursive_mnt(mnt, &nd->path, NULL); |
| 934 | out_unlock: | 940 | out_unlock: |
| 935 | mutex_unlock(&nd->path.dentry->d_inode->i_mutex); | 941 | mutex_unlock(&nd->path.dentry->d_inode->i_mutex); |
| 936 | if (!err) | 942 | if (!err) |
| @@ -1059,7 +1065,8 @@ static inline int tree_contains_unbindable(struct vfsmount *mnt) | |||
| 1059 | */ | 1065 | */ |
| 1060 | static noinline int do_move_mount(struct nameidata *nd, char *old_name) | 1066 | static noinline int do_move_mount(struct nameidata *nd, char *old_name) |
| 1061 | { | 1067 | { |
| 1062 | struct nameidata old_nd, parent_nd; | 1068 | struct nameidata old_nd; |
| 1069 | struct path parent_path; | ||
| 1063 | struct vfsmount *p; | 1070 | struct vfsmount *p; |
| 1064 | int err = 0; | 1071 | int err = 0; |
| 1065 | if (!capable(CAP_SYS_ADMIN)) | 1072 | if (!capable(CAP_SYS_ADMIN)) |
| @@ -1114,21 +1121,19 @@ static noinline int do_move_mount(struct nameidata *nd, char *old_name) | |||
| 1114 | if (p == old_nd.path.mnt) | 1121 | if (p == old_nd.path.mnt) |
| 1115 | goto out1; | 1122 | goto out1; |
| 1116 | 1123 | ||
| 1117 | err = attach_recursive_mnt(old_nd.path.mnt, nd, &parent_nd); | 1124 | err = attach_recursive_mnt(old_nd.path.mnt, &nd->path, &parent_path); |
| 1118 | if (err) | 1125 | if (err) |
| 1119 | goto out1; | 1126 | goto out1; |
| 1120 | 1127 | ||
| 1121 | spin_lock(&vfsmount_lock); | ||
| 1122 | /* if the mount is moved, it should no longer be expire | 1128 | /* if the mount is moved, it should no longer be expire |
| 1123 | * automatically */ | 1129 | * automatically */ |
| 1124 | list_del_init(&old_nd.path.mnt->mnt_expire); | 1130 | list_del_init(&old_nd.path.mnt->mnt_expire); |
| 1125 | spin_unlock(&vfsmount_lock); | ||
| 1126 | out1: | 1131 | out1: |
| 1127 | mutex_unlock(&nd->path.dentry->d_inode->i_mutex); | 1132 | mutex_unlock(&nd->path.dentry->d_inode->i_mutex); |
| 1128 | out: | 1133 | out: |
| 1129 | up_write(&namespace_sem); | 1134 | up_write(&namespace_sem); |
| 1130 | if (!err) | 1135 | if (!err) |
| 1131 | path_put(&parent_nd.path); | 1136 | path_put(&parent_path); |
| 1132 | path_put(&old_nd.path); | 1137 | path_put(&old_nd.path); |
| 1133 | return err; | 1138 | return err; |
| 1134 | } | 1139 | } |
| @@ -1189,12 +1194,9 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, | |||
| 1189 | if ((err = graft_tree(newmnt, nd))) | 1194 | if ((err = graft_tree(newmnt, nd))) |
| 1190 | goto unlock; | 1195 | goto unlock; |
| 1191 | 1196 | ||
| 1192 | if (fslist) { | 1197 | if (fslist) /* add to the specified expiration list */ |
| 1193 | /* add to the specified expiration list */ | ||
| 1194 | spin_lock(&vfsmount_lock); | ||
| 1195 | list_add_tail(&newmnt->mnt_expire, fslist); | 1198 | list_add_tail(&newmnt->mnt_expire, fslist); |
| 1196 | spin_unlock(&vfsmount_lock); | 1199 | |
| 1197 | } | ||
| 1198 | up_write(&namespace_sem); | 1200 | up_write(&namespace_sem); |
| 1199 | return 0; | 1201 | return 0; |
| 1200 | 1202 | ||
| @@ -1206,75 +1208,6 @@ unlock: | |||
| 1206 | 1208 | ||
| 1207 | EXPORT_SYMBOL_GPL(do_add_mount); | 1209 | EXPORT_SYMBOL_GPL(do_add_mount); |
| 1208 | 1210 | ||
| 1209 | static void expire_mount(struct vfsmount *mnt, struct list_head *mounts, | ||
| 1210 | struct list_head *umounts) | ||
| 1211 | { | ||
| 1212 | spin_lock(&vfsmount_lock); | ||
| 1213 | |||
| 1214 | /* | ||
| 1215 | * Check if mount is still attached, if not, let whoever holds it deal | ||
| 1216 | * with the sucker | ||
| 1217 | */ | ||
| 1218 | if (mnt->mnt_parent == mnt) { | ||
| 1219 | spin_unlock(&vfsmount_lock); | ||
| 1220 | return; | ||
| 1221 | } | ||
| 1222 | |||
| 1223 | /* | ||
| 1224 | * Check that it is still dead: the count should now be 2 - as | ||
| 1225 | * contributed by the vfsmount parent and the mntget above | ||
| 1226 | */ | ||
| 1227 | if (!propagate_mount_busy(mnt, 2)) { | ||
| 1228 | /* delete from the namespace */ | ||
| 1229 | touch_mnt_namespace(mnt->mnt_ns); | ||
| 1230 | list_del_init(&mnt->mnt_list); | ||
| 1231 | mnt->mnt_ns = NULL; | ||
| 1232 | umount_tree(mnt, 1, umounts); | ||
| 1233 | spin_unlock(&vfsmount_lock); | ||
| 1234 | } else { | ||
| 1235 | /* | ||
| 1236 | * Someone brought it back to life whilst we didn't have any | ||
| 1237 | * locks held so return it to the expiration list | ||
| 1238 | */ | ||
| 1239 | list_add_tail(&mnt->mnt_expire, mounts); | ||
| 1240 | spin_unlock(&vfsmount_lock); | ||
| 1241 | } | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | /* | ||
| 1245 | * go through the vfsmounts we've just consigned to the graveyard to | ||
| 1246 | * - check that they're still dead | ||
| 1247 | * - delete the vfsmount from the appropriate namespace under lock | ||
| 1248 | * - dispose of the corpse | ||
| 1249 | */ | ||
| 1250 | static void expire_mount_list(struct list_head *graveyard, struct list_head *mounts) | ||
| 1251 | { | ||
| 1252 | struct mnt_namespace *ns; | ||
| 1253 | struct vfsmount *mnt; | ||
| 1254 | |||
| 1255 | while (!list_empty(graveyard)) { | ||
| 1256 | LIST_HEAD(umounts); | ||
| 1257 | mnt = list_first_entry(graveyard, struct vfsmount, mnt_expire); | ||
| 1258 | list_del_init(&mnt->mnt_expire); | ||
| 1259 | |||
| 1260 | /* don't do anything if the namespace is dead - all the | ||
| 1261 | * vfsmounts from it are going away anyway */ | ||
| 1262 | ns = mnt->mnt_ns; | ||
| 1263 | if (!ns || !ns->root) | ||
| 1264 | continue; | ||
| 1265 | get_mnt_ns(ns); | ||
| 1266 | |||
| 1267 | spin_unlock(&vfsmount_lock); | ||
| 1268 | down_write(&namespace_sem); | ||
| 1269 | expire_mount(mnt, mounts, &umounts); | ||
| 1270 | up_write(&namespace_sem); | ||
| 1271 | release_mounts(&umounts); | ||
| 1272 | mntput(mnt); | ||
| 1273 | put_mnt_ns(ns); | ||
| 1274 | spin_lock(&vfsmount_lock); | ||
| 1275 | } | ||
| 1276 | } | ||
| 1277 | |||
| 1278 | /* | 1211 | /* |
| 1279 | * process a list of expirable mountpoints with the intent of discarding any | 1212 | * process a list of expirable mountpoints with the intent of discarding any |
| 1280 | * mountpoints that aren't in use and haven't been touched since last we came | 1213 | * mountpoints that aren't in use and haven't been touched since last we came |
| @@ -1284,10 +1217,12 @@ void mark_mounts_for_expiry(struct list_head *mounts) | |||
| 1284 | { | 1217 | { |
| 1285 | struct vfsmount *mnt, *next; | 1218 | struct vfsmount *mnt, *next; |
| 1286 | LIST_HEAD(graveyard); | 1219 | LIST_HEAD(graveyard); |
| 1220 | LIST_HEAD(umounts); | ||
| 1287 | 1221 | ||
| 1288 | if (list_empty(mounts)) | 1222 | if (list_empty(mounts)) |
| 1289 | return; | 1223 | return; |
| 1290 | 1224 | ||
| 1225 | down_write(&namespace_sem); | ||
| 1291 | spin_lock(&vfsmount_lock); | 1226 | spin_lock(&vfsmount_lock); |
| 1292 | 1227 | ||
| 1293 | /* extract from the expiration list every vfsmount that matches the | 1228 | /* extract from the expiration list every vfsmount that matches the |
| @@ -1298,16 +1233,19 @@ void mark_mounts_for_expiry(struct list_head *mounts) | |||
| 1298 | */ | 1233 | */ |
| 1299 | list_for_each_entry_safe(mnt, next, mounts, mnt_expire) { | 1234 | list_for_each_entry_safe(mnt, next, mounts, mnt_expire) { |
| 1300 | if (!xchg(&mnt->mnt_expiry_mark, 1) || | 1235 | if (!xchg(&mnt->mnt_expiry_mark, 1) || |
| 1301 | atomic_read(&mnt->mnt_count) != 1) | 1236 | propagate_mount_busy(mnt, 1)) |
| 1302 | continue; | 1237 | continue; |
| 1303 | |||
| 1304 | mntget(mnt); | ||
| 1305 | list_move(&mnt->mnt_expire, &graveyard); | 1238 | list_move(&mnt->mnt_expire, &graveyard); |
| 1306 | } | 1239 | } |
| 1307 | 1240 | while (!list_empty(&graveyard)) { | |
| 1308 | expire_mount_list(&graveyard, mounts); | 1241 | mnt = list_first_entry(&graveyard, struct vfsmount, mnt_expire); |
| 1309 | 1242 | touch_mnt_namespace(mnt->mnt_ns); | |
| 1243 | umount_tree(mnt, 1, &umounts); | ||
| 1244 | } | ||
| 1310 | spin_unlock(&vfsmount_lock); | 1245 | spin_unlock(&vfsmount_lock); |
| 1246 | up_write(&namespace_sem); | ||
| 1247 | |||
| 1248 | release_mounts(&umounts); | ||
| 1311 | } | 1249 | } |
| 1312 | 1250 | ||
| 1313 | EXPORT_SYMBOL_GPL(mark_mounts_for_expiry); | 1251 | EXPORT_SYMBOL_GPL(mark_mounts_for_expiry); |
| @@ -1343,7 +1281,6 @@ resume: | |||
| 1343 | } | 1281 | } |
| 1344 | 1282 | ||
| 1345 | if (!propagate_mount_busy(mnt, 1)) { | 1283 | if (!propagate_mount_busy(mnt, 1)) { |
| 1346 | mntget(mnt); | ||
| 1347 | list_move_tail(&mnt->mnt_expire, graveyard); | 1284 | list_move_tail(&mnt->mnt_expire, graveyard); |
| 1348 | found++; | 1285 | found++; |
| 1349 | } | 1286 | } |
| @@ -1363,22 +1300,22 @@ resume: | |||
| 1363 | * process a list of expirable mountpoints with the intent of discarding any | 1300 | * process a list of expirable mountpoints with the intent of discarding any |
| 1364 | * submounts of a specific parent mountpoint | 1301 | * submounts of a specific parent mountpoint |
| 1365 | */ | 1302 | */ |
| 1366 | void shrink_submounts(struct vfsmount *mountpoint, struct list_head *mounts) | 1303 | static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts) |
| 1367 | { | 1304 | { |
| 1368 | LIST_HEAD(graveyard); | 1305 | LIST_HEAD(graveyard); |
| 1369 | int found; | 1306 | struct vfsmount *m; |
| 1370 | |||
| 1371 | spin_lock(&vfsmount_lock); | ||
| 1372 | 1307 | ||
| 1373 | /* extract submounts of 'mountpoint' from the expiration list */ | 1308 | /* extract submounts of 'mountpoint' from the expiration list */ |
| 1374 | while ((found = select_submounts(mountpoint, &graveyard)) != 0) | 1309 | while (select_submounts(mnt, &graveyard)) { |
| 1375 | expire_mount_list(&graveyard, mounts); | 1310 | while (!list_empty(&graveyard)) { |
| 1376 | 1311 | m = list_first_entry(&graveyard, struct vfsmount, | |
| 1377 | spin_unlock(&vfsmount_lock); | 1312 | mnt_expire); |
| 1313 | touch_mnt_namespace(mnt->mnt_ns); | ||
| 1314 | umount_tree(mnt, 1, umounts); | ||
| 1315 | } | ||
| 1316 | } | ||
| 1378 | } | 1317 | } |
| 1379 | 1318 | ||
| 1380 | EXPORT_SYMBOL_GPL(shrink_submounts); | ||
| 1381 | |||
| 1382 | /* | 1319 | /* |
| 1383 | * Some copy_from_user() implementations do not return the exact number of | 1320 | * Some copy_from_user() implementations do not return the exact number of |
| 1384 | * bytes remaining to copy on a fault. But copy_mount_options() requires that. | 1321 | * bytes remaining to copy on a fault. But copy_mount_options() requires that. |
| @@ -1683,7 +1620,7 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path) | |||
| 1683 | path_put(&old_pwd); | 1620 | path_put(&old_pwd); |
| 1684 | } | 1621 | } |
| 1685 | 1622 | ||
| 1686 | static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd) | 1623 | static void chroot_fs_refs(struct path *old_root, struct path *new_root) |
| 1687 | { | 1624 | { |
| 1688 | struct task_struct *g, *p; | 1625 | struct task_struct *g, *p; |
| 1689 | struct fs_struct *fs; | 1626 | struct fs_struct *fs; |
| @@ -1695,12 +1632,12 @@ static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd) | |||
| 1695 | if (fs) { | 1632 | if (fs) { |
| 1696 | atomic_inc(&fs->count); | 1633 | atomic_inc(&fs->count); |
| 1697 | task_unlock(p); | 1634 | task_unlock(p); |
| 1698 | if (fs->root.dentry == old_nd->path.dentry | 1635 | if (fs->root.dentry == old_root->dentry |
| 1699 | && fs->root.mnt == old_nd->path.mnt) | 1636 | && fs->root.mnt == old_root->mnt) |
| 1700 | set_fs_root(fs, &new_nd->path); | 1637 | set_fs_root(fs, new_root); |
| 1701 | if (fs->pwd.dentry == old_nd->path.dentry | 1638 | if (fs->pwd.dentry == old_root->dentry |
| 1702 | && fs->pwd.mnt == old_nd->path.mnt) | 1639 | && fs->pwd.mnt == old_root->mnt) |
| 1703 | set_fs_pwd(fs, &new_nd->path); | 1640 | set_fs_pwd(fs, new_root); |
| 1704 | put_fs_struct(fs); | 1641 | put_fs_struct(fs); |
| 1705 | } else | 1642 | } else |
| 1706 | task_unlock(p); | 1643 | task_unlock(p); |
| @@ -1737,7 +1674,8 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
| 1737 | const char __user * put_old) | 1674 | const char __user * put_old) |
| 1738 | { | 1675 | { |
| 1739 | struct vfsmount *tmp; | 1676 | struct vfsmount *tmp; |
| 1740 | struct nameidata new_nd, old_nd, parent_nd, root_parent, user_nd; | 1677 | struct nameidata new_nd, old_nd, user_nd; |
| 1678 | struct path parent_path, root_parent; | ||
| 1741 | int error; | 1679 | int error; |
| 1742 | 1680 | ||
| 1743 | if (!capable(CAP_SYS_ADMIN)) | 1681 | if (!capable(CAP_SYS_ADMIN)) |
| @@ -1811,19 +1749,19 @@ asmlinkage long sys_pivot_root(const char __user * new_root, | |||
| 1811 | goto out3; | 1749 | goto out3; |
| 1812 | } else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry)) | 1750 | } else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry)) |
| 1813 | goto out3; | 1751 | goto out3; |
| 1814 | detach_mnt(new_nd.path.mnt, &parent_nd); | 1752 | detach_mnt(new_nd.path.mnt, &parent_path); |
| 1815 | detach_mnt(user_nd.path.mnt, &root_parent); | 1753 | detach_mnt(user_nd.path.mnt, &root_parent); |
| 1816 | /* mount old root on put_old */ | 1754 | /* mount old root on put_old */ |
| 1817 | attach_mnt(user_nd.path.mnt, &old_nd); | 1755 | attach_mnt(user_nd.path.mnt, &old_nd.path); |
| 1818 | /* mount new_root on / */ | 1756 | /* mount new_root on / */ |
| 1819 | attach_mnt(new_nd.path.mnt, &root_parent); | 1757 | attach_mnt(new_nd.path.mnt, &root_parent); |
| 1820 | touch_mnt_namespace(current->nsproxy->mnt_ns); | 1758 | touch_mnt_namespace(current->nsproxy->mnt_ns); |
| 1821 | spin_unlock(&vfsmount_lock); | 1759 | spin_unlock(&vfsmount_lock); |
| 1822 | chroot_fs_refs(&user_nd, &new_nd); | 1760 | chroot_fs_refs(&user_nd.path, &new_nd.path); |
| 1823 | security_sb_post_pivotroot(&user_nd, &new_nd); | 1761 | security_sb_post_pivotroot(&user_nd, &new_nd); |
| 1824 | error = 0; | 1762 | error = 0; |
| 1825 | path_put(&root_parent.path); | 1763 | path_put(&root_parent); |
| 1826 | path_put(&parent_nd.path); | 1764 | path_put(&parent_path); |
| 1827 | out2: | 1765 | out2: |
| 1828 | mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex); | 1766 | mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex); |
| 1829 | up_write(&namespace_sem); | 1767 | up_write(&namespace_sem); |
