]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/pnode.c
powerpc/mm: Remove __this_fixmap_does_not_exist()
[karo-tx-linux.git] / fs / pnode.c
index 06a793f4ae38739c3bb70b3c5a35d5adf6b8e3c1..5bc7896d122ae700fc76c3a71e123149d013b92a 100644 (file)
@@ -322,6 +322,21 @@ out:
        return ret;
 }
 
+static struct mount *find_topper(struct mount *mnt)
+{
+       /* If there is exactly one mount covering mnt completely return it. */
+       struct mount *child;
+
+       if (!list_is_singular(&mnt->mnt_mounts))
+               return NULL;
+
+       child = list_first_entry(&mnt->mnt_mounts, struct mount, mnt_child);
+       if (child->mnt_mountpoint != mnt->mnt.mnt_root)
+               return NULL;
+
+       return child;
+}
+
 /*
  * return true if the refcount is greater than count
  */
@@ -342,9 +357,8 @@ static inline int do_refcount_check(struct mount *mnt, int count)
  */
 int propagate_mount_busy(struct mount *mnt, int refcnt)
 {
-       struct mount *m, *child;
+       struct mount *m, *child, *topper;
        struct mount *parent = mnt->mnt_parent;
-       int ret = 0;
 
        if (mnt == parent)
                return do_refcount_check(mnt, refcnt);
@@ -359,12 +373,24 @@ int propagate_mount_busy(struct mount *mnt, int refcnt)
 
        for (m = propagation_next(parent, parent); m;
                        m = propagation_next(m, parent)) {
-               child = __lookup_mnt_last(&m->mnt, mnt->mnt_mountpoint);
-               if (child && list_empty(&child->mnt_mounts) &&
-                   (ret = do_refcount_check(child, 1)))
-                       break;
+               int count = 1;
+               child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint);
+               if (!child)
+                       continue;
+
+               /* Is there exactly one mount on the child that covers
+                * it completely whose reference should be ignored?
+                */
+               topper = find_topper(child);
+               if (topper)
+                       count += 1;
+               else if (!list_empty(&child->mnt_mounts))
+                       continue;
+
+               if (do_refcount_check(child, count))
+                       return 1;
        }
-       return ret;
+       return 0;
 }
 
 /*
@@ -381,7 +407,7 @@ void propagate_mount_unlock(struct mount *mnt)
 
        for (m = propagation_next(parent, parent); m;
                        m = propagation_next(m, parent)) {
-               child = __lookup_mnt_last(&m->mnt, mnt->mnt_mountpoint);
+               child = __lookup_mnt(&m->mnt, mnt->mnt_mountpoint);
                if (child)
                        child->mnt.mnt_flags &= ~MNT_LOCKED;
        }
@@ -399,9 +425,11 @@ static void mark_umount_candidates(struct mount *mnt)
 
        for (m = propagation_next(parent, parent); m;
                        m = propagation_next(m, parent)) {
-               struct mount *child = __lookup_mnt_last(&m->mnt,
+               struct mount *child = __lookup_mnt(&m->mnt,
                                                mnt->mnt_mountpoint);
-               if (child && (!IS_MNT_LOCKED(child) || IS_MNT_MARKED(m))) {
+               if (!child || (child->mnt.mnt_flags & MNT_UMOUNT))
+                       continue;
+               if (!IS_MNT_LOCKED(child) || IS_MNT_MARKED(m)) {
                        SET_MNT_MARK(child);
                }
        }
@@ -420,8 +448,8 @@ static void __propagate_umount(struct mount *mnt)
 
        for (m = propagation_next(parent, parent); m;
                        m = propagation_next(m, parent)) {
-
-               struct mount *child = __lookup_mnt_last(&m->mnt,
+               struct mount *topper;
+               struct mount *child = __lookup_mnt(&m->mnt,
                                                mnt->mnt_mountpoint);
                /*
                 * umount the child only if the child has no children
@@ -430,6 +458,15 @@ static void __propagate_umount(struct mount *mnt)
                if (!child || !IS_MNT_MARKED(child))
                        continue;
                CLEAR_MNT_MARK(child);
+
+               /* If there is exactly one mount covering all of child
+                * replace child with that mount.
+                */
+               topper = find_topper(child);
+               if (topper)
+                       mnt_change_mountpoint(child->mnt_parent, child->mnt_mp,
+                                             topper);
+
                if (list_empty(&child->mnt_mounts)) {
                        list_del_init(&child->mnt_child);
                        child->mnt.mnt_flags |= MNT_UMOUNT;