mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 08:38:45 +02:00 
			
		
		
		
	vfs: Add a function to lazily unmount all mounts from any dentry.
The new function detach_mounts comes in two pieces.  The first piece
is a static inline test of d_mounpoint that returns immediately
without taking any locks if d_mounpoint is not set.  In the common
case when mountpoints are absent this allows the vfs to continue
running with it's same cacheline foot print.
The second piece of detach_mounts __detach_mounts actually does the
work and it assumes that a mountpoint is present so it is slow and
takes namespace_sem for write, and then locks the mount hash (aka
mount_lock) after a struct mountpoint has been found.
With those two locks held each entry on the list of mounts on a
mountpoint is selected and lazily unmounted until all of the mount
have been lazily unmounted.
v7: Wrote a proper change description and removed the changelog
    documenting deleted wrong turns.
Signed-off-by: Eric W. Biederman <ebiederman@twitter.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
			
			
This commit is contained in:
		
							parent
							
								
									e2dfa93546
								
							
						
					
					
						commit
						80b5dce8c5
					
				
					 2 changed files with 40 additions and 0 deletions
				
			
		|  | @ -87,6 +87,15 @@ extern struct mount *__lookup_mnt_last(struct vfsmount *, struct dentry *); | ||||||
| 
 | 
 | ||||||
| extern bool legitimize_mnt(struct vfsmount *, unsigned); | extern bool legitimize_mnt(struct vfsmount *, unsigned); | ||||||
| 
 | 
 | ||||||
|  | extern void __detach_mounts(struct dentry *dentry); | ||||||
|  | 
 | ||||||
|  | static inline void detach_mounts(struct dentry *dentry) | ||||||
|  | { | ||||||
|  | 	if (!d_mountpoint(dentry)) | ||||||
|  | 		return; | ||||||
|  | 	__detach_mounts(dentry); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static inline void get_mnt_ns(struct mnt_namespace *ns) | static inline void get_mnt_ns(struct mnt_namespace *ns) | ||||||
| { | { | ||||||
| 	atomic_inc(&ns->count); | 	atomic_inc(&ns->count); | ||||||
|  |  | ||||||
|  | @ -1468,6 +1468,37 @@ static int do_umount(struct mount *mnt, int flags) | ||||||
| 	return retval; | 	return retval; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * __detach_mounts - lazily unmount all mounts on the specified dentry | ||||||
|  |  * | ||||||
|  |  * During unlink, rmdir, and d_drop it is possible to loose the path | ||||||
|  |  * to an existing mountpoint, and wind up leaking the mount. | ||||||
|  |  * detach_mounts allows lazily unmounting those mounts instead of | ||||||
|  |  * leaking them. | ||||||
|  |  * | ||||||
|  |  * The caller may hold dentry->d_inode->i_mutex. | ||||||
|  |  */ | ||||||
|  | void __detach_mounts(struct dentry *dentry) | ||||||
|  | { | ||||||
|  | 	struct mountpoint *mp; | ||||||
|  | 	struct mount *mnt; | ||||||
|  | 
 | ||||||
|  | 	namespace_lock(); | ||||||
|  | 	mp = lookup_mountpoint(dentry); | ||||||
|  | 	if (!mp) | ||||||
|  | 		goto out_unlock; | ||||||
|  | 
 | ||||||
|  | 	lock_mount_hash(); | ||||||
|  | 	while (!hlist_empty(&mp->m_list)) { | ||||||
|  | 		mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list); | ||||||
|  | 		umount_tree(mnt, 2); | ||||||
|  | 	} | ||||||
|  | 	unlock_mount_hash(); | ||||||
|  | 	put_mountpoint(mp); | ||||||
|  | out_unlock: | ||||||
|  | 	namespace_unlock(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* 
 | /* 
 | ||||||
|  * Is the caller allowed to modify his namespace? |  * Is the caller allowed to modify his namespace? | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Eric W. Biederman
						Eric W. Biederman