Skip to content

Commit aab771f

Browse files
author
Al Viro
committed
take freeing of emptied mnt_namespace to namespace_unlock()
Freeing of a namespace must be delayed until after we'd dealt with mount notifications (in namespace_unlock()). The reasons are not immediately obvious (they are buried in ->prev_ns handling in mnt_notify()), and having that free_mnt_ns() explicitly called after namespace_unlock() is asking for trouble - it does feel like they should be OK to free as soon as they've been emptied. Make the things more explicit by setting 'emptied_ns' under namespace_sem and having namespace_unlock() free the sucker as soon as it's safe to free. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
1 parent 6632068 commit aab771f

1 file changed

Lines changed: 12 additions & 15 deletions

File tree

fs/namespace.c

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ static struct kmem_cache *mnt_cache __ro_after_init;
7979
static DECLARE_RWSEM(namespace_sem);
8080
static HLIST_HEAD(unmounted); /* protected by namespace_sem */
8181
static LIST_HEAD(ex_mountpoints); /* protected by namespace_sem */
82+
static struct mnt_namespace *emptied_ns; /* protected by namespace_sem */
8283
static DEFINE_SEQLOCK(mnt_ns_tree_lock);
8384

8485
#ifdef CONFIG_FSNOTIFY
@@ -1730,15 +1731,18 @@ static bool need_notify_mnt_list(void)
17301731
}
17311732
#endif
17321733

1734+
static void free_mnt_ns(struct mnt_namespace *);
17331735
static void namespace_unlock(void)
17341736
{
17351737
struct hlist_head head;
17361738
struct hlist_node *p;
17371739
struct mount *m;
1740+
struct mnt_namespace *ns = emptied_ns;
17381741
LIST_HEAD(list);
17391742

17401743
hlist_move_list(&unmounted, &head);
17411744
list_splice_init(&ex_mountpoints, &list);
1745+
emptied_ns = NULL;
17421746

17431747
if (need_notify_mnt_list()) {
17441748
/*
@@ -1752,6 +1756,11 @@ static void namespace_unlock(void)
17521756
} else {
17531757
up_write(&namespace_sem);
17541758
}
1759+
if (unlikely(ns)) {
1760+
/* Make sure we notice when we leak mounts. */
1761+
VFS_WARN_ON_ONCE(!mnt_ns_empty(ns));
1762+
free_mnt_ns(ns);
1763+
}
17551764

17561765
shrink_dentry_list(&list);
17571766

@@ -2335,12 +2344,10 @@ void drop_collected_paths(struct path *paths, struct path *prealloc)
23352344
kfree(paths);
23362345
}
23372346

2338-
static void free_mnt_ns(struct mnt_namespace *);
23392347
static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *, bool);
23402348

23412349
void dissolve_on_fput(struct vfsmount *mnt)
23422350
{
2343-
struct mnt_namespace *ns;
23442351
struct mount *m = real_mount(mnt);
23452352

23462353
/*
@@ -2362,15 +2369,11 @@ void dissolve_on_fput(struct vfsmount *mnt)
23622369
if (!anon_ns_root(m))
23632370
return;
23642371

2365-
ns = m->mnt_ns;
2372+
emptied_ns = m->mnt_ns;
23662373
lock_mount_hash();
23672374
umount_tree(m, UMOUNT_CONNECTED);
23682375
unlock_mount_hash();
23692376
}
2370-
2371-
/* Make sure we notice when we leak mounts. */
2372-
VFS_WARN_ON_ONCE(!mnt_ns_empty(ns));
2373-
free_mnt_ns(ns);
23742377
}
23752378

23762379
static bool __has_locked_children(struct mount *mnt, struct dentry *dentry)
@@ -2678,6 +2681,7 @@ static int attach_recursive_mnt(struct mount *source_mnt,
26782681
} else {
26792682
if (source_mnt->mnt_ns) {
26802683
/* move from anon - the caller will destroy */
2684+
emptied_ns = source_mnt->mnt_ns;
26812685
for (p = source_mnt; p; p = next_mnt(p, source_mnt))
26822686
move_from_ns(p);
26832687
}
@@ -3656,13 +3660,6 @@ static int do_move_mount(struct path *old_path,
36563660
err = attach_recursive_mnt(old, p, mp.mp);
36573661
out:
36583662
unlock_mount(&mp);
3659-
if (!err) {
3660-
if (is_anon_ns(ns)) {
3661-
/* Make sure we notice when we leak mounts. */
3662-
VFS_WARN_ON_ONCE(!mnt_ns_empty(ns));
3663-
free_mnt_ns(ns);
3664-
}
3665-
}
36663663
return err;
36673664
}
36683665

@@ -6153,11 +6150,11 @@ void put_mnt_ns(struct mnt_namespace *ns)
61536150
if (!refcount_dec_and_test(&ns->ns.count))
61546151
return;
61556152
namespace_lock();
6153+
emptied_ns = ns;
61566154
lock_mount_hash();
61576155
umount_tree(ns->root, 0);
61586156
unlock_mount_hash();
61596157
namespace_unlock();
6160-
free_mnt_ns(ns);
61616158
}
61626159

61636160
struct vfsmount *kern_mount(struct file_system_type *type)

0 commit comments

Comments
 (0)