diff options
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 28 |
1 files changed, 20 insertions, 8 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 98d27da43304..a7f91265ea67 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -695,9 +695,6 @@ static struct mountpoint *lookup_mountpoint(struct dentry *dentry) | |||
695 | 695 | ||
696 | hlist_for_each_entry(mp, chain, m_hash) { | 696 | hlist_for_each_entry(mp, chain, m_hash) { |
697 | if (mp->m_dentry == dentry) { | 697 | if (mp->m_dentry == dentry) { |
698 | /* might be worth a WARN_ON() */ | ||
699 | if (d_unlinked(dentry)) | ||
700 | return ERR_PTR(-ENOENT); | ||
701 | mp->m_count++; | 698 | mp->m_count++; |
702 | return mp; | 699 | return mp; |
703 | } | 700 | } |
@@ -711,6 +708,9 @@ static struct mountpoint *get_mountpoint(struct dentry *dentry) | |||
711 | int ret; | 708 | int ret; |
712 | 709 | ||
713 | if (d_mountpoint(dentry)) { | 710 | if (d_mountpoint(dentry)) { |
711 | /* might be worth a WARN_ON() */ | ||
712 | if (d_unlinked(dentry)) | ||
713 | return ERR_PTR(-ENOENT); | ||
714 | mountpoint: | 714 | mountpoint: |
715 | read_seqlock_excl(&mount_lock); | 715 | read_seqlock_excl(&mount_lock); |
716 | mp = lookup_mountpoint(dentry); | 716 | mp = lookup_mountpoint(dentry); |
@@ -1540,8 +1540,13 @@ static int do_umount(struct mount *mnt, int flags) | |||
1540 | 1540 | ||
1541 | namespace_lock(); | 1541 | namespace_lock(); |
1542 | lock_mount_hash(); | 1542 | lock_mount_hash(); |
1543 | event++; | ||
1544 | 1543 | ||
1544 | /* Recheck MNT_LOCKED with the locks held */ | ||
1545 | retval = -EINVAL; | ||
1546 | if (mnt->mnt.mnt_flags & MNT_LOCKED) | ||
1547 | goto out; | ||
1548 | |||
1549 | event++; | ||
1545 | if (flags & MNT_DETACH) { | 1550 | if (flags & MNT_DETACH) { |
1546 | if (!list_empty(&mnt->mnt_list)) | 1551 | if (!list_empty(&mnt->mnt_list)) |
1547 | umount_tree(mnt, UMOUNT_PROPAGATE); | 1552 | umount_tree(mnt, UMOUNT_PROPAGATE); |
@@ -1555,6 +1560,7 @@ static int do_umount(struct mount *mnt, int flags) | |||
1555 | retval = 0; | 1560 | retval = 0; |
1556 | } | 1561 | } |
1557 | } | 1562 | } |
1563 | out: | ||
1558 | unlock_mount_hash(); | 1564 | unlock_mount_hash(); |
1559 | namespace_unlock(); | 1565 | namespace_unlock(); |
1560 | return retval; | 1566 | return retval; |
@@ -1645,7 +1651,7 @@ int ksys_umount(char __user *name, int flags) | |||
1645 | goto dput_and_out; | 1651 | goto dput_and_out; |
1646 | if (!check_mnt(mnt)) | 1652 | if (!check_mnt(mnt)) |
1647 | goto dput_and_out; | 1653 | goto dput_and_out; |
1648 | if (mnt->mnt.mnt_flags & MNT_LOCKED) | 1654 | if (mnt->mnt.mnt_flags & MNT_LOCKED) /* Check optimistically */ |
1649 | goto dput_and_out; | 1655 | goto dput_and_out; |
1650 | retval = -EPERM; | 1656 | retval = -EPERM; |
1651 | if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN)) | 1657 | if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN)) |
@@ -1728,8 +1734,14 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, | |||
1728 | for (s = r; s; s = next_mnt(s, r)) { | 1734 | for (s = r; s; s = next_mnt(s, r)) { |
1729 | if (!(flag & CL_COPY_UNBINDABLE) && | 1735 | if (!(flag & CL_COPY_UNBINDABLE) && |
1730 | IS_MNT_UNBINDABLE(s)) { | 1736 | IS_MNT_UNBINDABLE(s)) { |
1731 | s = skip_mnt_tree(s); | 1737 | if (s->mnt.mnt_flags & MNT_LOCKED) { |
1732 | continue; | 1738 | /* Both unbindable and locked. */ |
1739 | q = ERR_PTR(-EPERM); | ||
1740 | goto out; | ||
1741 | } else { | ||
1742 | s = skip_mnt_tree(s); | ||
1743 | continue; | ||
1744 | } | ||
1733 | } | 1745 | } |
1734 | if (!(flag & CL_COPY_MNT_NS_FILE) && | 1746 | if (!(flag & CL_COPY_MNT_NS_FILE) && |
1735 | is_mnt_ns_file(s->mnt.mnt_root)) { | 1747 | is_mnt_ns_file(s->mnt.mnt_root)) { |
@@ -1782,7 +1794,7 @@ void drop_collected_mounts(struct vfsmount *mnt) | |||
1782 | { | 1794 | { |
1783 | namespace_lock(); | 1795 | namespace_lock(); |
1784 | lock_mount_hash(); | 1796 | lock_mount_hash(); |
1785 | umount_tree(real_mount(mnt), UMOUNT_SYNC); | 1797 | umount_tree(real_mount(mnt), 0); |
1786 | unlock_mount_hash(); | 1798 | unlock_mount_hash(); |
1787 | namespace_unlock(); | 1799 | namespace_unlock(); |
1788 | } | 1800 | } |