mirror of https://gitee.com/openkylin/linux.git
switch the remnants of releasing the mountpoint away from fs_pin
We used to need rather convoluted ordering trickery to guarantee that dput() of ex-mountpoints happens before the final mntput() of the same. Since we don't need that anymore, there's no point playing with fs_pin for that. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
2763d11912
commit
56cbb429d9
14
fs/fs_pin.c
14
fs/fs_pin.c
|
@ -19,18 +19,12 @@ void pin_remove(struct fs_pin *pin)
|
||||||
spin_unlock_irq(&pin->wait.lock);
|
spin_unlock_irq(&pin->wait.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pin_insert_group(struct fs_pin *pin, struct vfsmount *m, struct hlist_head *p)
|
|
||||||
{
|
|
||||||
spin_lock(&pin_lock);
|
|
||||||
if (p)
|
|
||||||
hlist_add_head(&pin->s_list, p);
|
|
||||||
hlist_add_head(&pin->m_list, &real_mount(m)->mnt_pins);
|
|
||||||
spin_unlock(&pin_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pin_insert(struct fs_pin *pin, struct vfsmount *m)
|
void pin_insert(struct fs_pin *pin, struct vfsmount *m)
|
||||||
{
|
{
|
||||||
pin_insert_group(pin, m, &m->mnt_sb->s_pins);
|
spin_lock(&pin_lock);
|
||||||
|
hlist_add_head(&pin->s_list, &m->mnt_sb->s_pins);
|
||||||
|
hlist_add_head(&pin->m_list, &real_mount(m)->mnt_pins);
|
||||||
|
spin_unlock(&pin_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pin_kill(struct fs_pin *p)
|
void pin_kill(struct fs_pin *p)
|
||||||
|
|
|
@ -58,7 +58,10 @@ struct mount {
|
||||||
struct mount *mnt_master; /* slave is on master->mnt_slave_list */
|
struct mount *mnt_master; /* slave is on master->mnt_slave_list */
|
||||||
struct mnt_namespace *mnt_ns; /* containing namespace */
|
struct mnt_namespace *mnt_ns; /* containing namespace */
|
||||||
struct mountpoint *mnt_mp; /* where is it mounted */
|
struct mountpoint *mnt_mp; /* where is it mounted */
|
||||||
|
union {
|
||||||
struct hlist_node mnt_mp_list; /* list mounts with the same mountpoint */
|
struct hlist_node mnt_mp_list; /* list mounts with the same mountpoint */
|
||||||
|
struct hlist_node mnt_umount;
|
||||||
|
};
|
||||||
struct list_head mnt_umounting; /* list entry for umount propagation */
|
struct list_head mnt_umounting; /* list entry for umount propagation */
|
||||||
#ifdef CONFIG_FSNOTIFY
|
#ifdef CONFIG_FSNOTIFY
|
||||||
struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks;
|
struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks;
|
||||||
|
@ -68,7 +71,7 @@ struct mount {
|
||||||
int mnt_group_id; /* peer group identifier */
|
int mnt_group_id; /* peer group identifier */
|
||||||
int mnt_expiry_mark; /* true if marked for expiry */
|
int mnt_expiry_mark; /* true if marked for expiry */
|
||||||
struct hlist_head mnt_pins;
|
struct hlist_head mnt_pins;
|
||||||
struct fs_pin mnt_umount;
|
struct hlist_head mnt_stuck_children;
|
||||||
} __randomize_layout;
|
} __randomize_layout;
|
||||||
|
|
||||||
#define MNT_NS_INTERNAL ERR_PTR(-EINVAL) /* distinct from any mnt_namespace */
|
#define MNT_NS_INTERNAL ERR_PTR(-EINVAL) /* distinct from any mnt_namespace */
|
||||||
|
|
|
@ -171,13 +171,6 @@ unsigned int mnt_get_count(struct mount *mnt)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drop_mountpoint(struct fs_pin *p)
|
|
||||||
{
|
|
||||||
struct mount *m = container_of(p, struct mount, mnt_umount);
|
|
||||||
pin_remove(p);
|
|
||||||
mntput(&m->mnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct mount *alloc_vfsmnt(const char *name)
|
static struct mount *alloc_vfsmnt(const char *name)
|
||||||
{
|
{
|
||||||
struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
|
struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
|
||||||
|
@ -215,7 +208,7 @@ static struct mount *alloc_vfsmnt(const char *name)
|
||||||
INIT_LIST_HEAD(&mnt->mnt_slave);
|
INIT_LIST_HEAD(&mnt->mnt_slave);
|
||||||
INIT_HLIST_NODE(&mnt->mnt_mp_list);
|
INIT_HLIST_NODE(&mnt->mnt_mp_list);
|
||||||
INIT_LIST_HEAD(&mnt->mnt_umounting);
|
INIT_LIST_HEAD(&mnt->mnt_umounting);
|
||||||
init_fs_pin(&mnt->mnt_umount, drop_mountpoint);
|
INIT_HLIST_HEAD(&mnt->mnt_stuck_children);
|
||||||
}
|
}
|
||||||
return mnt;
|
return mnt;
|
||||||
|
|
||||||
|
@ -1087,19 +1080,22 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
|
||||||
|
|
||||||
static void cleanup_mnt(struct mount *mnt)
|
static void cleanup_mnt(struct mount *mnt)
|
||||||
{
|
{
|
||||||
|
struct hlist_node *p;
|
||||||
|
struct mount *m;
|
||||||
/*
|
/*
|
||||||
* This probably indicates that somebody messed
|
* The warning here probably indicates that somebody messed
|
||||||
* up a mnt_want/drop_write() pair. If this
|
* up a mnt_want/drop_write() pair. If this happens, the
|
||||||
* happens, the filesystem was probably unable
|
* filesystem was probably unable to make r/w->r/o transitions.
|
||||||
* to make r/w->r/o transitions.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* The locking used to deal with mnt_count decrement provides barriers,
|
* The locking used to deal with mnt_count decrement provides barriers,
|
||||||
* so mnt_get_writers() below is safe.
|
* so mnt_get_writers() below is safe.
|
||||||
*/
|
*/
|
||||||
WARN_ON(mnt_get_writers(mnt));
|
WARN_ON(mnt_get_writers(mnt));
|
||||||
if (unlikely(mnt->mnt_pins.first))
|
if (unlikely(mnt->mnt_pins.first))
|
||||||
mnt_pin_kill(mnt);
|
mnt_pin_kill(mnt);
|
||||||
|
hlist_for_each_entry_safe(m, p, &mnt->mnt_stuck_children, mnt_umount) {
|
||||||
|
hlist_del(&m->mnt_umount);
|
||||||
|
mntput(&m->mnt);
|
||||||
|
}
|
||||||
fsnotify_vfsmount_delete(&mnt->mnt);
|
fsnotify_vfsmount_delete(&mnt->mnt);
|
||||||
dput(mnt->mnt.mnt_root);
|
dput(mnt->mnt.mnt_root);
|
||||||
deactivate_super(mnt->mnt.mnt_sb);
|
deactivate_super(mnt->mnt.mnt_sb);
|
||||||
|
@ -1168,6 +1164,7 @@ static void mntput_no_expire(struct mount *mnt)
|
||||||
struct mount *p, *tmp;
|
struct mount *p, *tmp;
|
||||||
list_for_each_entry_safe(p, tmp, &mnt->mnt_mounts, mnt_child) {
|
list_for_each_entry_safe(p, tmp, &mnt->mnt_mounts, mnt_child) {
|
||||||
__put_mountpoint(unhash_mnt(p), &list);
|
__put_mountpoint(unhash_mnt(p), &list);
|
||||||
|
hlist_add_head(&p->mnt_umount, &mnt->mnt_stuck_children);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unlock_mount_hash();
|
unlock_mount_hash();
|
||||||
|
@ -1360,6 +1357,8 @@ EXPORT_SYMBOL(may_umount);
|
||||||
static void namespace_unlock(void)
|
static void namespace_unlock(void)
|
||||||
{
|
{
|
||||||
struct hlist_head head;
|
struct hlist_head head;
|
||||||
|
struct hlist_node *p;
|
||||||
|
struct mount *m;
|
||||||
LIST_HEAD(list);
|
LIST_HEAD(list);
|
||||||
|
|
||||||
hlist_move_list(&unmounted, &head);
|
hlist_move_list(&unmounted, &head);
|
||||||
|
@ -1374,7 +1373,10 @@ static void namespace_unlock(void)
|
||||||
|
|
||||||
synchronize_rcu_expedited();
|
synchronize_rcu_expedited();
|
||||||
|
|
||||||
group_pin_kill(&head);
|
hlist_for_each_entry_safe(m, p, &head, mnt_umount) {
|
||||||
|
hlist_del(&m->mnt_umount);
|
||||||
|
mntput(&m->mnt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void namespace_lock(void)
|
static inline void namespace_lock(void)
|
||||||
|
@ -1461,8 +1463,6 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
|
||||||
|
|
||||||
disconnect = disconnect_mount(p, how);
|
disconnect = disconnect_mount(p, how);
|
||||||
|
|
||||||
pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt,
|
|
||||||
disconnect ? &unmounted : NULL);
|
|
||||||
if (mnt_has_parent(p)) {
|
if (mnt_has_parent(p)) {
|
||||||
mnt_add_count(p->mnt_parent, -1);
|
mnt_add_count(p->mnt_parent, -1);
|
||||||
if (!disconnect) {
|
if (!disconnect) {
|
||||||
|
@ -1470,6 +1470,7 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
|
||||||
list_add_tail(&p->mnt_child, &p->mnt_parent->mnt_mounts);
|
list_add_tail(&p->mnt_child, &p->mnt_parent->mnt_mounts);
|
||||||
} else {
|
} else {
|
||||||
umount_mnt(p);
|
umount_mnt(p);
|
||||||
|
hlist_add_head(&p->mnt_umount, &unmounted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
change_mnt_propagation(p, MS_PRIVATE);
|
change_mnt_propagation(p, MS_PRIVATE);
|
||||||
|
@ -1622,8 +1623,8 @@ void __detach_mounts(struct dentry *dentry)
|
||||||
while (!hlist_empty(&mp->m_list)) {
|
while (!hlist_empty(&mp->m_list)) {
|
||||||
mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
|
mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
|
||||||
if (mnt->mnt.mnt_flags & MNT_UMOUNT) {
|
if (mnt->mnt.mnt_flags & MNT_UMOUNT) {
|
||||||
hlist_add_head(&mnt->mnt_umount.s_list, &unmounted);
|
|
||||||
umount_mnt(mnt);
|
umount_mnt(mnt);
|
||||||
|
hlist_add_head(&mnt->mnt_umount, &unmounted);
|
||||||
}
|
}
|
||||||
else umount_tree(mnt, UMOUNT_CONNECTED);
|
else umount_tree(mnt, UMOUNT_CONNECTED);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,5 @@ static inline void init_fs_pin(struct fs_pin *p, void (*kill)(struct fs_pin *))
|
||||||
}
|
}
|
||||||
|
|
||||||
void pin_remove(struct fs_pin *);
|
void pin_remove(struct fs_pin *);
|
||||||
void pin_insert_group(struct fs_pin *, struct vfsmount *, struct hlist_head *);
|
|
||||||
void pin_insert(struct fs_pin *, struct vfsmount *);
|
void pin_insert(struct fs_pin *, struct vfsmount *);
|
||||||
void pin_kill(struct fs_pin *);
|
void pin_kill(struct fs_pin *);
|
||||||
|
|
Loading…
Reference in New Issue