diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-03-28 18:23:01 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-03-28 18:23:01 -0400 |
commit | af8be4e4b316df36a00c1e52a9970c253783b57e (patch) | |
tree | 6d56665916e601ed6a933d6f85c22ee8512c6531 | |
parent | d478376cb0dc9ab16a2b6e02fd8cd1174e724c64 (diff) | |
parent | 6758f953d05378d907a164c67934cd86183d9c88 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6:
[PATCH] mnt_expire is protected by namespace_sem, no need for vfsmount_lock
[PATCH] do shrink_submounts() for all fs types
[PATCH] sanitize locking in mark_mounts_for_expiry() and shrink_submounts()
[PATCH] count ghost references to vfsmounts
[PATCH] reduce stack footprint in namespace.c
-rw-r--r-- | fs/afs/internal.h | 1 | ||||
-rw-r--r-- | fs/afs/mntpt.c | 8 | ||||
-rw-r--r-- | fs/afs/super.c | 1 | ||||
-rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 1 | ||||
-rw-r--r-- | fs/namespace.c | 200 | ||||
-rw-r--r-- | fs/nfs/super.c | 2 | ||||
-rw-r--r-- | fs/pnode.c | 2 | ||||
-rw-r--r-- | include/linux/mount.h | 2 |
8 files changed, 71 insertions, 146 deletions
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 5ca3625cd39e..9ba16edc0af2 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
@@ -573,7 +573,6 @@ extern const struct file_operations afs_mntpt_file_operations; | |||
573 | 573 | ||
574 | extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *); | 574 | extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *); |
575 | extern void afs_mntpt_kill_timer(void); | 575 | extern void afs_mntpt_kill_timer(void); |
576 | extern void afs_umount_begin(struct vfsmount *, int); | ||
577 | 576 | ||
578 | /* | 577 | /* |
579 | * proc.c | 578 | * proc.c |
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index a3510b8ba3e7..2f5503902c37 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c | |||
@@ -283,11 +283,3 @@ void afs_mntpt_kill_timer(void) | |||
283 | cancel_delayed_work(&afs_mntpt_expiry_timer); | 283 | cancel_delayed_work(&afs_mntpt_expiry_timer); |
284 | flush_scheduled_work(); | 284 | flush_scheduled_work(); |
285 | } | 285 | } |
286 | |||
287 | /* | ||
288 | * begin unmount by attempting to remove all automounted mountpoints we added | ||
289 | */ | ||
290 | void afs_umount_begin(struct vfsmount *vfsmnt, int flags) | ||
291 | { | ||
292 | shrink_submounts(vfsmnt, &afs_vfsmounts); | ||
293 | } | ||
diff --git a/fs/afs/super.c b/fs/afs/super.c index 36bbce45f44b..4b572b801d8d 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
@@ -50,7 +50,6 @@ static const struct super_operations afs_super_ops = { | |||
50 | .write_inode = afs_write_inode, | 50 | .write_inode = afs_write_inode, |
51 | .destroy_inode = afs_destroy_inode, | 51 | .destroy_inode = afs_destroy_inode, |
52 | .clear_inode = afs_clear_inode, | 52 | .clear_inode = afs_clear_inode, |
53 | .umount_begin = afs_umount_begin, | ||
54 | .put_super = afs_put_super, | 53 | .put_super = afs_put_super, |
55 | .show_options = generic_show_options, | 54 | .show_options = generic_show_options, |
56 | }; | 55 | }; |
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index a1a95b027136..56c924033b78 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
@@ -33,7 +33,6 @@ void dfs_shrink_umount_helper(struct vfsmount *vfsmnt) | |||
33 | { | 33 | { |
34 | mark_mounts_for_expiry(&cifs_dfs_automount_list); | 34 | mark_mounts_for_expiry(&cifs_dfs_automount_list); |
35 | mark_mounts_for_expiry(&cifs_dfs_automount_list); | 35 | mark_mounts_for_expiry(&cifs_dfs_automount_list); |
36 | shrink_submounts(vfsmnt, &cifs_dfs_automount_list); | ||
37 | } | 36 | } |
38 | 37 | ||
39 | /** | 38 | /** |
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); |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index dd4dfcd632ec..f9219024f31a 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -589,8 +589,6 @@ static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) | |||
589 | struct nfs_server *server = NFS_SB(vfsmnt->mnt_sb); | 589 | struct nfs_server *server = NFS_SB(vfsmnt->mnt_sb); |
590 | struct rpc_clnt *rpc; | 590 | struct rpc_clnt *rpc; |
591 | 591 | ||
592 | shrink_submounts(vfsmnt, &nfs_automount_list); | ||
593 | |||
594 | if (!(flags & MNT_FORCE)) | 592 | if (!(flags & MNT_FORCE)) |
595 | return; | 593 | return; |
596 | /* -EIO all pending I/O */ | 594 | /* -EIO all pending I/O */ |
diff --git a/fs/pnode.c b/fs/pnode.c index 05ba692bc540..1d8f5447f3f7 100644 --- a/fs/pnode.c +++ b/fs/pnode.c | |||
@@ -225,7 +225,7 @@ out: | |||
225 | */ | 225 | */ |
226 | static inline int do_refcount_check(struct vfsmount *mnt, int count) | 226 | static inline int do_refcount_check(struct vfsmount *mnt, int count) |
227 | { | 227 | { |
228 | int mycount = atomic_read(&mnt->mnt_count); | 228 | int mycount = atomic_read(&mnt->mnt_count) - mnt->mnt_ghosts; |
229 | return (mycount > count); | 229 | return (mycount > count); |
230 | } | 230 | } |
231 | 231 | ||
diff --git a/include/linux/mount.h b/include/linux/mount.h index 6d3047d8c91c..5ee2df217cdf 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h | |||
@@ -61,6 +61,7 @@ struct vfsmount { | |||
61 | atomic_t mnt_count; | 61 | atomic_t mnt_count; |
62 | int mnt_expiry_mark; /* true if marked for expiry */ | 62 | int mnt_expiry_mark; /* true if marked for expiry */ |
63 | int mnt_pinned; | 63 | int mnt_pinned; |
64 | int mnt_ghosts; | ||
64 | }; | 65 | }; |
65 | 66 | ||
66 | static inline struct vfsmount *mntget(struct vfsmount *mnt) | 67 | static inline struct vfsmount *mntget(struct vfsmount *mnt) |
@@ -98,7 +99,6 @@ extern int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, | |||
98 | int mnt_flags, struct list_head *fslist); | 99 | int mnt_flags, struct list_head *fslist); |
99 | 100 | ||
100 | extern void mark_mounts_for_expiry(struct list_head *mounts); | 101 | extern void mark_mounts_for_expiry(struct list_head *mounts); |
101 | extern void shrink_submounts(struct vfsmount *mountpoint, struct list_head *mounts); | ||
102 | 102 | ||
103 | extern spinlock_t vfsmount_lock; | 103 | extern spinlock_t vfsmount_lock; |
104 | extern dev_t name_to_dev_t(char *name); | 104 | extern dev_t name_to_dev_t(char *name); |