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)  	hlist_for_each_entry(mp, chain, m_hash) {  		if (mp->m_dentry == dentry) { -			/* might be worth a WARN_ON() */ -			if (d_unlinked(dentry)) -				return ERR_PTR(-ENOENT);  			mp->m_count++;  			return mp;  		} @@ -711,6 +708,9 @@ static struct mountpoint *get_mountpoint(struct dentry *dentry)  	int ret;  	if (d_mountpoint(dentry)) { +		/* might be worth a WARN_ON() */ +		if (d_unlinked(dentry)) +			return ERR_PTR(-ENOENT);  mountpoint:  		read_seqlock_excl(&mount_lock);  		mp = lookup_mountpoint(dentry); @@ -1540,8 +1540,13 @@ static int do_umount(struct mount *mnt, int flags)  	namespace_lock();  	lock_mount_hash(); -	event++; +	/* Recheck MNT_LOCKED with the locks held */ +	retval = -EINVAL; +	if (mnt->mnt.mnt_flags & MNT_LOCKED) +		goto out; + +	event++;  	if (flags & MNT_DETACH) {  		if (!list_empty(&mnt->mnt_list))  			umount_tree(mnt, UMOUNT_PROPAGATE); @@ -1555,6 +1560,7 @@ static int do_umount(struct mount *mnt, int flags)  			retval = 0;  		}  	} +out:  	unlock_mount_hash();  	namespace_unlock();  	return retval; @@ -1645,7 +1651,7 @@ int ksys_umount(char __user *name, int flags)  		goto dput_and_out;  	if (!check_mnt(mnt))  		goto dput_and_out; -	if (mnt->mnt.mnt_flags & MNT_LOCKED) +	if (mnt->mnt.mnt_flags & MNT_LOCKED) /* Check optimistically */  		goto dput_and_out;  	retval = -EPERM;  	if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN)) @@ -1728,8 +1734,14 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,  		for (s = r; s; s = next_mnt(s, r)) {  			if (!(flag & CL_COPY_UNBINDABLE) &&  			    IS_MNT_UNBINDABLE(s)) { -				s = skip_mnt_tree(s); -				continue; +				if (s->mnt.mnt_flags & MNT_LOCKED) { +					/* Both unbindable and locked. */ +					q = ERR_PTR(-EPERM); +					goto out; +				} else { +					s = skip_mnt_tree(s); +					continue; +				}  			}  			if (!(flag & CL_COPY_MNT_NS_FILE) &&  			    is_mnt_ns_file(s->mnt.mnt_root)) { @@ -1782,7 +1794,7 @@ void drop_collected_mounts(struct vfsmount *mnt)  {  	namespace_lock();  	lock_mount_hash(); -	umount_tree(real_mount(mnt), UMOUNT_SYNC); +	umount_tree(real_mount(mnt), 0);  	unlock_mount_hash();  	namespace_unlock();  }  | 
