mirror of
https://github.com/torvalds/linux.git
synced 2026-06-02 11:33:28 +02:00
take ->mnt_expire handling under mount_lock [read_seqlock_excl]
Doesn't take much massage, and we no longer need to make sure that by the time of final mntput() the victim has been removed from the list. Makes life safer for ->d_automount() instances... Rules: * all ->mnt_expire accesses are under mount_lock. * insertion into the list is done by mnt_set_expiry(), and caller (->d_automount() instance) must hold a reference to mount in question. It shouldn't be done more than once for a mount. * if a mount on an expiry list is not yet mounted, it will be ignored by anything that walks that list. * if the final mntput() finds its victim still on an expiry list (in which case it must've never been mounted - umount_tree() would've taken it out), it will remove the victim from the list. Reviewed-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
a8c764e1a5
commit
ec3265a245
|
|
@ -1353,13 +1353,6 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
|
|||
list_add(&mnt->mnt_slave, &old->mnt_slave);
|
||||
mnt->mnt_master = old->mnt_master;
|
||||
}
|
||||
|
||||
/* stick the duplicate mount on the same expiry list
|
||||
* as the original if that was on one */
|
||||
if (flag & CL_EXPIRE) {
|
||||
if (!list_empty(&old->mnt_expire))
|
||||
list_add(&mnt->mnt_expire, &old->mnt_expire);
|
||||
}
|
||||
return mnt;
|
||||
|
||||
out_free:
|
||||
|
|
@ -1452,6 +1445,8 @@ static void mntput_no_expire(struct mount *mnt)
|
|||
rcu_read_unlock();
|
||||
|
||||
list_del(&mnt->mnt_instance);
|
||||
if (unlikely(!list_empty(&mnt->mnt_expire)))
|
||||
list_del(&mnt->mnt_expire);
|
||||
|
||||
if (unlikely(!list_empty(&mnt->mnt_mounts))) {
|
||||
struct mount *p, *tmp;
|
||||
|
|
@ -2273,6 +2268,13 @@ struct mount *copy_tree(struct mount *src_root, struct dentry *dentry,
|
|||
lock_mount_hash();
|
||||
if (src_mnt->mnt.mnt_flags & MNT_LOCKED)
|
||||
dst_mnt->mnt.mnt_flags |= MNT_LOCKED;
|
||||
if (unlikely(flag & CL_EXPIRE)) {
|
||||
/* stick the duplicate mount on the same expiry
|
||||
* list as the original if that was on one */
|
||||
if (!list_empty(&src_mnt->mnt_expire))
|
||||
list_add(&dst_mnt->mnt_expire,
|
||||
&src_mnt->mnt_expire);
|
||||
}
|
||||
list_add_tail(&dst_mnt->mnt_list, &res->mnt_list);
|
||||
attach_mnt(dst_mnt, dst_parent, src_parent->mnt_mp);
|
||||
unlock_mount_hash();
|
||||
|
|
@ -3891,12 +3893,6 @@ int finish_automount(struct vfsmount *m, const struct path *path)
|
|||
namespace_unlock();
|
||||
inode_unlock(dentry->d_inode);
|
||||
discard:
|
||||
/* remove m from any expiration list it may be on */
|
||||
if (!list_empty(&mnt->mnt_expire)) {
|
||||
namespace_lock();
|
||||
list_del_init(&mnt->mnt_expire);
|
||||
namespace_unlock();
|
||||
}
|
||||
mntput(m);
|
||||
return err;
|
||||
}
|
||||
|
|
@ -3908,11 +3904,9 @@ int finish_automount(struct vfsmount *m, const struct path *path)
|
|||
*/
|
||||
void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list)
|
||||
{
|
||||
namespace_lock();
|
||||
|
||||
read_seqlock_excl(&mount_lock);
|
||||
list_add_tail(&real_mount(mnt)->mnt_expire, expiry_list);
|
||||
|
||||
namespace_unlock();
|
||||
read_sequnlock_excl(&mount_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(mnt_set_expiry);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user