diff options
| author | Mark Brown <[email protected]> | 2015-10-12 18:09:27 +0100 | 
|---|---|---|
| committer | Mark Brown <[email protected]> | 2015-10-12 18:09:27 +0100 | 
| commit | 79828b4fa835f73cdaf4bffa48696abdcbea9d02 (patch) | |
| tree | 5e0fa7156acb75ba603022bc807df8f2fedb97a8 /fs/namespace.c | |
| parent | 721b51fcf91898299d96f4b72cb9434cda29dce6 (diff) | |
| parent | 8c1a9d6323abf0fb1e5dad96cf3f1c783505ea5a (diff) | |
Merge remote-tracking branch 'asoc/fix/rt5645' into asoc-fix-rt5645
Diffstat (limited to 'fs/namespace.c')
| -rw-r--r-- | fs/namespace.c | 75 | 
1 files changed, 58 insertions, 17 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index c7cb8a526c05..0570729c87fd 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1361,6 +1361,36 @@ enum umount_tree_flags {  	UMOUNT_PROPAGATE = 2,  	UMOUNT_CONNECTED = 4,  }; + +static bool disconnect_mount(struct mount *mnt, enum umount_tree_flags how) +{ +	/* Leaving mounts connected is only valid for lazy umounts */ +	if (how & UMOUNT_SYNC) +		return true; + +	/* A mount without a parent has nothing to be connected to */ +	if (!mnt_has_parent(mnt)) +		return true; + +	/* Because the reference counting rules change when mounts are +	 * unmounted and connected, umounted mounts may not be +	 * connected to mounted mounts. +	 */ +	if (!(mnt->mnt_parent->mnt.mnt_flags & MNT_UMOUNT)) +		return true; + +	/* Has it been requested that the mount remain connected? */ +	if (how & UMOUNT_CONNECTED) +		return false; + +	/* Is the mount locked such that it needs to remain connected? */ +	if (IS_MNT_LOCKED(mnt)) +		return false; + +	/* By default disconnect the mount */ +	return true; +} +  /*   * mount_lock must be held   * namespace_sem must be held for write @@ -1398,10 +1428,7 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)  		if (how & UMOUNT_SYNC)  			p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; -		disconnect = !(((how & UMOUNT_CONNECTED) && -				mnt_has_parent(p) && -				(p->mnt_parent->mnt.mnt_flags & MNT_UMOUNT)) || -			       IS_MNT_LOCKED_AND_LAZY(p)); +		disconnect = disconnect_mount(p, how);  		pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt,  				 disconnect ? &unmounted : NULL); @@ -1538,11 +1565,8 @@ void __detach_mounts(struct dentry *dentry)  	while (!hlist_empty(&mp->m_list)) {  		mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);  		if (mnt->mnt.mnt_flags & MNT_UMOUNT) { -			struct mount *p, *tmp; -			list_for_each_entry_safe(p, tmp, &mnt->mnt_mounts,  mnt_child) { -				hlist_add_head(&p->mnt_umount.s_list, &unmounted); -				umount_mnt(p); -			} +			hlist_add_head(&mnt->mnt_umount.s_list, &unmounted); +			umount_mnt(mnt);  		}  		else umount_tree(mnt, UMOUNT_CONNECTED);  	} @@ -3194,6 +3218,8 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)  	down_read(&namespace_sem);  	list_for_each_entry(mnt, &ns->list, mnt_list) {  		struct mount *child; +		int mnt_flags; +  		if (mnt->mnt.mnt_sb->s_type != type)  			continue; @@ -3203,17 +3229,30 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)  		if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root)  			continue; +		/* Read the mount flags and filter out flags that +		 * may safely be ignored. +		 */ +		mnt_flags = mnt->mnt.mnt_flags; +		if (mnt->mnt.mnt_sb->s_iflags & SB_I_NOEXEC) +			mnt_flags &= ~(MNT_LOCK_NOSUID | MNT_LOCK_NOEXEC); +  		/* Verify the mount flags are equal to or more permissive  		 * than the proposed new mount.  		 */ -		if ((mnt->mnt.mnt_flags & MNT_LOCK_READONLY) && +		if ((mnt_flags & MNT_LOCK_READONLY) &&  		    !(new_flags & MNT_READONLY))  			continue; -		if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) && +		if ((mnt_flags & MNT_LOCK_NODEV) &&  		    !(new_flags & MNT_NODEV))  			continue; -		if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) && -		    ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK))) +		if ((mnt_flags & MNT_LOCK_NOSUID) && +		    !(new_flags & MNT_NOSUID)) +			continue; +		if ((mnt_flags & MNT_LOCK_NOEXEC) && +		    !(new_flags & MNT_NOEXEC)) +			continue; +		if ((mnt_flags & MNT_LOCK_ATIME) && +		    ((mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK)))  			continue;  		/* This mount is not fully visible if there are any @@ -3223,16 +3262,18 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags)  		list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {  			struct inode *inode = child->mnt_mountpoint->d_inode;  			/* Only worry about locked mounts */ -			if (!(mnt->mnt.mnt_flags & MNT_LOCKED)) +			if (!(mnt_flags & MNT_LOCKED))  				continue;  			/* Is the directory permanetly empty? */  			if (!is_empty_dir_inode(inode))  				goto next;  		}  		/* Preserve the locked attributes */ -		*new_mnt_flags |= mnt->mnt.mnt_flags & (MNT_LOCK_READONLY | \ -							MNT_LOCK_NODEV    | \ -							MNT_LOCK_ATIME); +		*new_mnt_flags |= mnt_flags & (MNT_LOCK_READONLY | \ +					       MNT_LOCK_NODEV    | \ +					       MNT_LOCK_NOSUID   | \ +					       MNT_LOCK_NOEXEC   | \ +					       MNT_LOCK_ATIME);  		visible = true;  		goto found;  	next:	;  |