diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2011-01-15 20:08:44 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-01-16 13:47:01 -0500 |
commit | 7b8a53fd815deb39542085897743fa0063f9fe06 (patch) | |
tree | 1fe7d7f6192b3300a12d2e6af80b9601f23f94f8 /fs/namespace.c | |
parent | b650c858c26bd9ba29ebc82d30f09355845a294a (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>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 8 |
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 | */ |
1227 | void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) | 1227 | void 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 | ||
1251 | static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts); | 1253 | static void shrink_submounts(struct vfsmount *mnt, struct list_head *umounts); |