saner umount_tree()/release_mounts(), part 1
[linux-2.6-block.git] / fs / namespace.c
index d7bb5a55cf364a371c5e91846fa419f5ec15e803..0d91711a3160c380a08547dd05e8f2a9f8054057 100644 (file)
@@ -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;
 }