aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2011-01-15 20:08:44 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2011-01-16 13:47:01 -0500
commit7b8a53fd815deb39542085897743fa0063f9fe06 (patch)
tree1fe7d7f6192b3300a12d2e6af80b9601f23f94f8
parentb650c858c26bd9ba29ebc82d30f09355845a294a (diff)
fix old umount_tree() breakage
Expiry-related code calls umount_tree() several times with the same list to collect vfsmounts to. Which is fine, except that umount_tree() implicitly assumed that the list would be empty on each call - it moves the victims over there and then iterates through the list kicking them out. It's *almost* idempotent, so everything nearly worked. However, mnt->ghosts handling (and thus expirability checks) had been broken - that part was not idempotent... The fix is trivial - use local temporary list, splice it to the the collector list when we are through. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/namespace.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index bfcb701f9490..d7fc05fac753 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1226,15 +1226,16 @@ void release_mounts(struct list_head *head)
1226 */ 1226 */
1227void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) 1227void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill)
1228{ 1228{
1229 LIST_HEAD(tmp_list);
1229 struct vfsmount *p; 1230 struct vfsmount *p;
1230 1231
1231 for (p = mnt; p; p = next_mnt(p, mnt)) 1232 for (p = mnt; p; p = next_mnt(p, mnt))
1232 list_move(&p->mnt_hash, kill); 1233 list_move(&p->mnt_hash, &tmp_list);
1233 1234
1234 if (propagate) 1235 if (propagate)
1235 propagate_umount(kill); 1236 propagate_umount(&tmp_list);
1236 1237
1237 list_for_each_entry(p, kill, mnt_hash) { 1238 list_for_each_entry(p, &tmp_list, mnt_hash) {
1238 list_del_init(&p->mnt_expire); 1239 list_del_init(&p->mnt_expire);
1239 list_del_init(&p->mnt_list); 1240 list_del_init(&p->mnt_list);
1240 __touch_mnt_namespace(p->mnt_ns); 1241 __touch_mnt_namespace(p->mnt_ns);
@@ -1246,6 +1247,7 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill)
1246 } 1247 }
1247 change_mnt_propagation(p, MS_PRIVATE); 1248 change_mnt_propagation(p, MS_PRIVATE);
1248 } 1249 }
1250 list_splice(&tmp_list, kill);
1249} 1251}
1250 1252
1251static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts); 1253static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts);