Skip to content

Commit 70fbcdf

Browse files
Ram PaiLinus Torvalds
authored andcommitted
[PATCH] umount_tree() locking change
umount is done under the protection of the namespace semaphore. This can lead to intresting deadlocks when the last reference to a mount is released, if filesystem code is in sufficiently nasty state. This collects all the to-be-released-mounts and releases them after releasing the namespace semaphore. That both reduces the time we are holding namespace semaphore and gets the things more robust. Idea proposed by Al Viro. Signed-off-by: Ram Pai <[email protected]> Signed-off-by: Al Viro <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 5b83d2c commit 70fbcdf

File tree

1 file changed

+51
-33
lines changed

1 file changed

+51
-33
lines changed

fs/namespace.c

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -394,39 +394,53 @@ int may_umount(struct vfsmount *mnt)
394394

395395
EXPORT_SYMBOL(may_umount);
396396

397-
static void umount_tree(struct vfsmount *mnt)
397+
static void release_mounts(struct list_head *head)
398+
{
399+
struct vfsmount *mnt;
400+
while(!list_empty(head)) {
401+
mnt = list_entry(head->next, struct vfsmount, mnt_hash);
402+
list_del_init(&mnt->mnt_hash);
403+
if (mnt->mnt_parent != mnt) {
404+
struct dentry *dentry;
405+
struct vfsmount *m;
406+
spin_lock(&vfsmount_lock);
407+
dentry = mnt->mnt_mountpoint;
408+
m = mnt->mnt_parent;
409+
mnt->mnt_mountpoint = mnt->mnt_root;
410+
mnt->mnt_parent = mnt;
411+
spin_unlock(&vfsmount_lock);
412+
dput(dentry);
413+
mntput(m);
414+
}
415+
mntput(mnt);
416+
}
417+
}
418+
419+
static void umount_tree(struct vfsmount *mnt, struct list_head *kill)
398420
{
399421
struct vfsmount *p;
400-
LIST_HEAD(kill);
401422

402423
for (p = mnt; p; p = next_mnt(p, mnt)) {
403-
list_del(&p->mnt_list);
404-
list_add(&p->mnt_list, &kill);
405-
__touch_namespace(p->mnt_namespace);
406-
p->mnt_namespace = NULL;
424+
list_del(&p->mnt_hash);
425+
list_add(&p->mnt_hash, kill);
407426
}
408427

409-
while (!list_empty(&kill)) {
410-
mnt = list_entry(kill.next, struct vfsmount, mnt_list);
411-
list_del_init(&mnt->mnt_list);
412-
list_del_init(&mnt->mnt_expire);
413-
if (mnt->mnt_parent == mnt) {
414-
spin_unlock(&vfsmount_lock);
415-
} else {
416-
struct nameidata old_nd;
417-
detach_mnt(mnt, &old_nd);
418-
spin_unlock(&vfsmount_lock);
419-
path_release(&old_nd);
420-
}
421-
mntput(mnt);
422-
spin_lock(&vfsmount_lock);
428+
list_for_each_entry(p, kill, mnt_hash) {
429+
list_del_init(&p->mnt_expire);
430+
list_del_init(&p->mnt_list);
431+
__touch_namespace(p->mnt_namespace);
432+
p->mnt_namespace = NULL;
433+
list_del_init(&p->mnt_child);
434+
if (p->mnt_parent != p)
435+
mnt->mnt_mountpoint->d_mounted--;
423436
}
424437
}
425438

426439
static int do_umount(struct vfsmount *mnt, int flags)
427440
{
428441
struct super_block *sb = mnt->mnt_sb;
429442
int retval;
443+
LIST_HEAD(umount_list);
430444

431445
retval = security_sb_umount(mnt, flags);
432446
if (retval)
@@ -497,13 +511,14 @@ static int do_umount(struct vfsmount *mnt, int flags)
497511
retval = -EBUSY;
498512
if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) {
499513
if (!list_empty(&mnt->mnt_list))
500-
umount_tree(mnt);
514+
umount_tree(mnt, &umount_list);
501515
retval = 0;
502516
}
503517
spin_unlock(&vfsmount_lock);
504518
if (retval)
505519
security_sb_umount_busy(mnt);
506520
up_write(&current->namespace->sem);
521+
release_mounts(&umount_list);
507522
return retval;
508523
}
509524

@@ -616,9 +631,11 @@ static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry)
616631
return res;
617632
Enomem:
618633
if (res) {
634+
LIST_HEAD(umount_list);
619635
spin_lock(&vfsmount_lock);
620-
umount_tree(res);
636+
umount_tree(res, &umount_list);
621637
spin_unlock(&vfsmount_lock);
638+
release_mounts(&umount_list);
622639
}
623640
return NULL;
624641
}
@@ -698,9 +715,11 @@ static int do_loopback(struct nameidata *nd, char *old_name, int recurse)
698715

699716
err = graft_tree(mnt, nd);
700717
if (err) {
718+
LIST_HEAD(umount_list);
701719
spin_lock(&vfsmount_lock);
702-
umount_tree(mnt);
720+
umount_tree(mnt, &umount_list);
703721
spin_unlock(&vfsmount_lock);
722+
release_mounts(&umount_list);
704723
}
705724

706725
out:
@@ -875,7 +894,8 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd,
875894

876895
EXPORT_SYMBOL_GPL(do_add_mount);
877896

878-
static void expire_mount(struct vfsmount *mnt, struct list_head *mounts)
897+
static void expire_mount(struct vfsmount *mnt, struct list_head *mounts,
898+
struct list_head *umounts)
879899
{
880900
spin_lock(&vfsmount_lock);
881901

@@ -893,16 +913,12 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts)
893913
* contributed by the vfsmount parent and the mntget above
894914
*/
895915
if (atomic_read(&mnt->mnt_count) == 2) {
896-
struct nameidata old_nd;
897-
898916
/* delete from the namespace */
899917
touch_namespace(mnt->mnt_namespace);
900918
list_del_init(&mnt->mnt_list);
901919
mnt->mnt_namespace = NULL;
902-
detach_mnt(mnt, &old_nd);
920+
umount_tree(mnt, umounts);
903921
spin_unlock(&vfsmount_lock);
904-
path_release(&old_nd);
905-
mntput(mnt);
906922
} else {
907923
/*
908924
* Someone brought it back to life whilst we didn't have any
@@ -951,6 +967,7 @@ void mark_mounts_for_expiry(struct list_head *mounts)
951967
* - dispose of the corpse
952968
*/
953969
while (!list_empty(&graveyard)) {
970+
LIST_HEAD(umounts);
954971
mnt = list_entry(graveyard.next, struct vfsmount, mnt_expire);
955972
list_del_init(&mnt->mnt_expire);
956973

@@ -963,12 +980,11 @@ void mark_mounts_for_expiry(struct list_head *mounts)
963980

964981
spin_unlock(&vfsmount_lock);
965982
down_write(&namespace->sem);
966-
expire_mount(mnt, mounts);
983+
expire_mount(mnt, mounts, &umounts);
967984
up_write(&namespace->sem);
968-
985+
release_mounts(&umounts);
969986
mntput(mnt);
970987
put_namespace(namespace);
971-
972988
spin_lock(&vfsmount_lock);
973989
}
974990

@@ -1508,12 +1524,14 @@ void __init mnt_init(unsigned long mempages)
15081524
void __put_namespace(struct namespace *namespace)
15091525
{
15101526
struct vfsmount *root = namespace->root;
1527+
LIST_HEAD(umount_list);
15111528
namespace->root = NULL;
15121529
spin_unlock(&vfsmount_lock);
15131530
down_write(&namespace->sem);
15141531
spin_lock(&vfsmount_lock);
1515-
umount_tree(root);
1532+
umount_tree(root, &umount_list);
15161533
spin_unlock(&vfsmount_lock);
15171534
up_write(&namespace->sem);
1535+
release_mounts(&umount_list);
15181536
kfree(namespace);
15191537
}

0 commit comments

Comments
 (0)