diff options
-rw-r--r-- | fs/namespace.c | 32 |
1 files changed, 23 insertions, 9 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 3b648da55d87..9db3ce397a83 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -621,12 +621,20 @@ struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) | |||
621 | struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry) | 621 | struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry) |
622 | { | 622 | { |
623 | struct list_head *head = m_hash(mnt, dentry); | 623 | struct list_head *head = m_hash(mnt, dentry); |
624 | struct mount *p; | 624 | struct mount *p, *res = NULL; |
625 | 625 | ||
626 | list_for_each_entry_reverse(p, head, mnt_hash) | 626 | list_for_each_entry(p, head, mnt_hash) |
627 | if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) | 627 | if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) |
628 | return p; | 628 | goto found; |
629 | return NULL; | 629 | return res; |
630 | found: | ||
631 | res = p; | ||
632 | list_for_each_entry_continue(p, head, mnt_hash) { | ||
633 | if (&p->mnt_parent->mnt != mnt || p->mnt_mountpoint != dentry) | ||
634 | break; | ||
635 | res = p; | ||
636 | } | ||
637 | return res; | ||
630 | } | 638 | } |
631 | 639 | ||
632 | /* | 640 | /* |
@@ -769,14 +777,14 @@ static void attach_mnt(struct mount *mnt, | |||
769 | struct mountpoint *mp) | 777 | struct mountpoint *mp) |
770 | { | 778 | { |
771 | mnt_set_mountpoint(parent, mp, mnt); | 779 | mnt_set_mountpoint(parent, mp, mnt); |
772 | list_add_tail(&mnt->mnt_hash, m_hash(&parent->mnt, mp->m_dentry)); | 780 | list_add(&mnt->mnt_hash, m_hash(&parent->mnt, mp->m_dentry)); |
773 | list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); | 781 | list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); |
774 | } | 782 | } |
775 | 783 | ||
776 | /* | 784 | /* |
777 | * vfsmount lock must be held for write | 785 | * vfsmount lock must be held for write |
778 | */ | 786 | */ |
779 | static void commit_tree(struct mount *mnt) | 787 | static void commit_tree(struct mount *mnt, struct mount *shadows) |
780 | { | 788 | { |
781 | struct mount *parent = mnt->mnt_parent; | 789 | struct mount *parent = mnt->mnt_parent; |
782 | struct mount *m; | 790 | struct mount *m; |
@@ -791,7 +799,10 @@ static void commit_tree(struct mount *mnt) | |||
791 | 799 | ||
792 | list_splice(&head, n->list.prev); | 800 | list_splice(&head, n->list.prev); |
793 | 801 | ||
794 | list_add_tail(&mnt->mnt_hash, | 802 | if (shadows) |
803 | list_add(&mnt->mnt_hash, &shadows->mnt_hash); | ||
804 | else | ||
805 | list_add(&mnt->mnt_hash, | ||
795 | m_hash(&parent->mnt, mnt->mnt_mountpoint)); | 806 | m_hash(&parent->mnt, mnt->mnt_mountpoint)); |
796 | list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); | 807 | list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); |
797 | touch_mnt_namespace(n); | 808 | touch_mnt_namespace(n); |
@@ -1659,12 +1670,15 @@ static int attach_recursive_mnt(struct mount *source_mnt, | |||
1659 | touch_mnt_namespace(source_mnt->mnt_ns); | 1670 | touch_mnt_namespace(source_mnt->mnt_ns); |
1660 | } else { | 1671 | } else { |
1661 | mnt_set_mountpoint(dest_mnt, dest_mp, source_mnt); | 1672 | mnt_set_mountpoint(dest_mnt, dest_mp, source_mnt); |
1662 | commit_tree(source_mnt); | 1673 | commit_tree(source_mnt, NULL); |
1663 | } | 1674 | } |
1664 | 1675 | ||
1665 | list_for_each_entry_safe(child, p, &tree_list, mnt_hash) { | 1676 | list_for_each_entry_safe(child, p, &tree_list, mnt_hash) { |
1677 | struct mount *q; | ||
1666 | list_del_init(&child->mnt_hash); | 1678 | list_del_init(&child->mnt_hash); |
1667 | commit_tree(child); | 1679 | q = __lookup_mnt_last(&child->mnt_parent->mnt, |
1680 | child->mnt_mountpoint); | ||
1681 | commit_tree(child, q); | ||
1668 | } | 1682 | } |
1669 | unlock_mount_hash(); | 1683 | unlock_mount_hash(); |
1670 | 1684 | ||