saner umount_tree()/release_mounts(), part 1
global list of release_mounts() fodder, protected by namespace_sem; eventually, all umount_tree() callers will use it as kill list. Helper picking the contents of that list, releasing namespace_sem and doing release_mounts() on what it got. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Родитель
84d17192d2
Коммит
e3197d83d6
|
@ -1119,6 +1119,8 @@ int may_umount(struct vfsmount *mnt)
|
|||
|
||||
EXPORT_SYMBOL(may_umount);
|
||||
|
||||
static LIST_HEAD(unmounted); /* protected by namespace_sem */
|
||||
|
||||
void release_mounts(struct list_head *head)
|
||||
{
|
||||
struct mount *mnt;
|
||||
|
@ -1143,6 +1145,14 @@ void release_mounts(struct list_head *head)
|
|||
}
|
||||
}
|
||||
|
||||
static void namespace_unlock(void)
|
||||
{
|
||||
LIST_HEAD(head);
|
||||
list_splice_init(&unmounted, &head);
|
||||
up_write(&namespace_sem);
|
||||
release_mounts(&head);
|
||||
}
|
||||
|
||||
/*
|
||||
* vfsmount lock must be held for write
|
||||
* namespace_sem must be held for write
|
||||
|
@ -1252,17 +1262,16 @@ static int do_umount(struct mount *mnt, int flags)
|
|||
event++;
|
||||
|
||||
if (!(flags & MNT_DETACH))
|
||||
shrink_submounts(mnt, &umount_list);
|
||||
shrink_submounts(mnt, &unmounted);
|
||||
|
||||
retval = -EBUSY;
|
||||
if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) {
|
||||
if (!list_empty(&mnt->mnt_list))
|
||||
umount_tree(mnt, 1, &umount_list);
|
||||
umount_tree(mnt, 1, &unmounted);
|
||||
retval = 0;
|
||||
}
|
||||
br_write_unlock(&vfsmount_lock);
|
||||
up_write(&namespace_sem);
|
||||
release_mounts(&umount_list);
|
||||
namespace_unlock();
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче