forked from mirrors/linux
		
	[PATCH] shared mount handling: bind and rbind
Implement handling of MS_BIND in presense of shared mounts (see Documentation/sharedsubtree.txt in the end of patch series for detailed description). Signed-off-by: Ram Pai <linuxram@us.ibm.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
		
							parent
							
								
									03e06e68ff
								
							
						
					
					
						commit
						b90fa9ae8f
					
				
					 4 changed files with 204 additions and 22 deletions
				
			
		
							
								
								
									
										126
									
								
								fs/namespace.c
									
									
									
									
									
								
							
							
						
						
									
										126
									
								
								fs/namespace.c
									
									
									
									
									
								
							| 
						 | 
					@ -28,8 +28,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int __init init_rootfs(void);
 | 
					extern int __init init_rootfs(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CL_EXPIRE 	0x01
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CONFIG_SYSFS
 | 
					#ifdef CONFIG_SYSFS
 | 
				
			||||||
extern int __init sysfs_init(void);
 | 
					extern int __init sysfs_init(void);
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
| 
						 | 
					@ -145,13 +143,43 @@ static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd)
 | 
				
			||||||
	old_nd->dentry->d_mounted--;
 | 
						old_nd->dentry->d_mounted--;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry,
 | 
				
			||||||
 | 
								struct vfsmount *child_mnt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						child_mnt->mnt_parent = mntget(mnt);
 | 
				
			||||||
 | 
						child_mnt->mnt_mountpoint = dget(dentry);
 | 
				
			||||||
 | 
						dentry->d_mounted++;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void attach_mnt(struct vfsmount *mnt, struct nameidata *nd)
 | 
					static void attach_mnt(struct vfsmount *mnt, struct nameidata *nd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mnt->mnt_parent = mntget(nd->mnt);
 | 
						mnt_set_mountpoint(nd->mnt, nd->dentry, mnt);
 | 
				
			||||||
	mnt->mnt_mountpoint = dget(nd->dentry);
 | 
						list_add_tail(&mnt->mnt_hash, mount_hashtable +
 | 
				
			||||||
	list_add(&mnt->mnt_hash, mount_hashtable + hash(nd->mnt, nd->dentry));
 | 
								hash(nd->mnt, nd->dentry));
 | 
				
			||||||
	list_add_tail(&mnt->mnt_child, &nd->mnt->mnt_mounts);
 | 
						list_add_tail(&mnt->mnt_child, &nd->mnt->mnt_mounts);
 | 
				
			||||||
	nd->dentry->d_mounted++;
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * the caller must hold vfsmount_lock
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void commit_tree(struct vfsmount *mnt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct vfsmount *parent = mnt->mnt_parent;
 | 
				
			||||||
 | 
						struct vfsmount *m;
 | 
				
			||||||
 | 
						LIST_HEAD(head);
 | 
				
			||||||
 | 
						struct namespace *n = parent->mnt_namespace;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BUG_ON(parent == mnt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_add_tail(&head, &mnt->mnt_list);
 | 
				
			||||||
 | 
						list_for_each_entry(m, &head, mnt_list)
 | 
				
			||||||
 | 
							m->mnt_namespace = n;
 | 
				
			||||||
 | 
						list_splice(&head, n->list.prev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_add_tail(&mnt->mnt_hash, mount_hashtable +
 | 
				
			||||||
 | 
									hash(parent, mnt->mnt_mountpoint));
 | 
				
			||||||
 | 
						list_add_tail(&mnt->mnt_child, &parent->mnt_mounts);
 | 
				
			||||||
 | 
						touch_namespace(n);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root)
 | 
					static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root)
 | 
				
			||||||
| 
						 | 
					@ -183,7 +211,11 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
 | 
				
			||||||
		mnt->mnt_root = dget(root);
 | 
							mnt->mnt_root = dget(root);
 | 
				
			||||||
		mnt->mnt_mountpoint = mnt->mnt_root;
 | 
							mnt->mnt_mountpoint = mnt->mnt_root;
 | 
				
			||||||
		mnt->mnt_parent = mnt;
 | 
							mnt->mnt_parent = mnt;
 | 
				
			||||||
		mnt->mnt_namespace = current->namespace;
 | 
					
 | 
				
			||||||
 | 
							if ((flag & CL_PROPAGATION) || IS_MNT_SHARED(old))
 | 
				
			||||||
 | 
								list_add(&mnt->mnt_share, &old->mnt_share);
 | 
				
			||||||
 | 
							if (flag & CL_MAKE_SHARED)
 | 
				
			||||||
 | 
								set_mnt_shared(mnt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* stick the duplicate mount on the same expiry list
 | 
							/* stick the duplicate mount on the same expiry list
 | 
				
			||||||
		 * as the original if that was on one */
 | 
							 * as the original if that was on one */
 | 
				
			||||||
| 
						 | 
					@ -379,7 +411,7 @@ int may_umount(struct vfsmount *mnt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXPORT_SYMBOL(may_umount);
 | 
					EXPORT_SYMBOL(may_umount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void release_mounts(struct list_head *head)
 | 
					void release_mounts(struct list_head *head)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct vfsmount *mnt;
 | 
						struct vfsmount *mnt;
 | 
				
			||||||
	while(!list_empty(head)) {
 | 
						while(!list_empty(head)) {
 | 
				
			||||||
| 
						 | 
					@ -401,7 +433,7 @@ static void release_mounts(struct list_head *head)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void umount_tree(struct vfsmount *mnt, struct list_head *kill)
 | 
					void umount_tree(struct vfsmount *mnt, struct list_head *kill)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct vfsmount *p;
 | 
						struct vfsmount *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -581,7 +613,7 @@ static int lives_below_in_same_fs(struct dentry *d, struct dentry *dentry)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry,
 | 
					struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry,
 | 
				
			||||||
					int flag)
 | 
										int flag)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct vfsmount *res, *p, *q, *r, *s;
 | 
						struct vfsmount *res, *p, *q, *r, *s;
 | 
				
			||||||
| 
						 | 
					@ -626,6 +658,67 @@ static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry,
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  @source_mnt : mount tree to be attached
 | 
				
			||||||
 | 
					 *  @nd        : place the mount tree @source_mnt is attached
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  NOTE: in the table below explains the semantics when a source mount
 | 
				
			||||||
 | 
					 *  of a given type is attached to a destination mount of a given type.
 | 
				
			||||||
 | 
					 * 	---------------------------------------------
 | 
				
			||||||
 | 
					 * 	|         BIND MOUNT OPERATION              |
 | 
				
			||||||
 | 
					 * 	|********************************************
 | 
				
			||||||
 | 
					 * 	| source-->| shared        |       private  |
 | 
				
			||||||
 | 
					 * 	| dest     |               |                |
 | 
				
			||||||
 | 
					 * 	|   |      |               |                |
 | 
				
			||||||
 | 
					 * 	|   v      |               |                |
 | 
				
			||||||
 | 
					 * 	|********************************************
 | 
				
			||||||
 | 
					 * 	|  shared  | shared (++)   |     shared (+) |
 | 
				
			||||||
 | 
					 * 	|          |               |                |
 | 
				
			||||||
 | 
					 * 	|non-shared| shared (+)    |      private   |
 | 
				
			||||||
 | 
					 * 	*********************************************
 | 
				
			||||||
 | 
					 * A bind operation clones the source mount and mounts the clone on the
 | 
				
			||||||
 | 
					 * destination mount.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * (++)  the cloned mount is propagated to all the mounts in the propagation
 | 
				
			||||||
 | 
					 * 	 tree of the destination mount and the cloned mount is added to
 | 
				
			||||||
 | 
					 * 	 the peer group of the source mount.
 | 
				
			||||||
 | 
					 * (+)   the cloned mount is created under the destination mount and is marked
 | 
				
			||||||
 | 
					 *       as shared. The cloned mount is added to the peer group of the source
 | 
				
			||||||
 | 
					 *       mount.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * if the source mount is a tree, the operations explained above is
 | 
				
			||||||
 | 
					 * applied to each mount in the tree.
 | 
				
			||||||
 | 
					 * Must be called without spinlocks held, since this function can sleep
 | 
				
			||||||
 | 
					 * in allocations.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static int attach_recursive_mnt(struct vfsmount *source_mnt,
 | 
				
			||||||
 | 
									struct nameidata *nd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						LIST_HEAD(tree_list);
 | 
				
			||||||
 | 
						struct vfsmount *dest_mnt = nd->mnt;
 | 
				
			||||||
 | 
						struct dentry *dest_dentry = nd->dentry;
 | 
				
			||||||
 | 
						struct vfsmount *child, *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (IS_MNT_SHARED(dest_mnt)) {
 | 
				
			||||||
 | 
							for (p = source_mnt; p; p = next_mnt(p, source_mnt))
 | 
				
			||||||
 | 
								set_mnt_shared(p);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spin_lock(&vfsmount_lock);
 | 
				
			||||||
 | 
						mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt);
 | 
				
			||||||
 | 
						commit_tree(source_mnt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						list_for_each_entry_safe(child, p, &tree_list, mnt_hash) {
 | 
				
			||||||
 | 
							list_del_init(&child->mnt_hash);
 | 
				
			||||||
 | 
							commit_tree(child);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						spin_unlock(&vfsmount_lock);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int graft_tree(struct vfsmount *mnt, struct nameidata *nd)
 | 
					static int graft_tree(struct vfsmount *mnt, struct nameidata *nd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
| 
						 | 
					@ -646,17 +739,8 @@ static int graft_tree(struct vfsmount *mnt, struct nameidata *nd)
 | 
				
			||||||
		goto out_unlock;
 | 
							goto out_unlock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = -ENOENT;
 | 
						err = -ENOENT;
 | 
				
			||||||
	spin_lock(&vfsmount_lock);
 | 
						if (IS_ROOT(nd->dentry) || !d_unhashed(nd->dentry))
 | 
				
			||||||
	if (IS_ROOT(nd->dentry) || !d_unhashed(nd->dentry)) {
 | 
							err = attach_recursive_mnt(mnt, nd);
 | 
				
			||||||
		struct list_head head;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		attach_mnt(mnt, nd);
 | 
					 | 
				
			||||||
		list_add_tail(&head, &mnt->mnt_list);
 | 
					 | 
				
			||||||
		list_splice(&head, current->namespace->list.prev);
 | 
					 | 
				
			||||||
		err = 0;
 | 
					 | 
				
			||||||
		touch_namespace(current->namespace);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	spin_unlock(&vfsmount_lock);
 | 
					 | 
				
			||||||
out_unlock:
 | 
					out_unlock:
 | 
				
			||||||
	up(&nd->dentry->d_inode->i_sem);
 | 
						up(&nd->dentry->d_inode->i_sem);
 | 
				
			||||||
	if (!err)
 | 
						if (!err)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										81
									
								
								fs/pnode.c
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								fs/pnode.c
									
									
									
									
									
								
							| 
						 | 
					@ -20,9 +20,88 @@ static inline struct vfsmount *next_peer(struct vfsmount *p)
 | 
				
			||||||
void change_mnt_propagation(struct vfsmount *mnt, int type)
 | 
					void change_mnt_propagation(struct vfsmount *mnt, int type)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (type == MS_SHARED) {
 | 
						if (type == MS_SHARED) {
 | 
				
			||||||
		mnt->mnt_flags |= MNT_SHARED;
 | 
							set_mnt_shared(mnt);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		list_del_init(&mnt->mnt_share);
 | 
							list_del_init(&mnt->mnt_share);
 | 
				
			||||||
		mnt->mnt_flags &= ~MNT_PNODE_MASK;
 | 
							mnt->mnt_flags &= ~MNT_PNODE_MASK;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * get the next mount in the propagation tree.
 | 
				
			||||||
 | 
					 * @m: the mount seen last
 | 
				
			||||||
 | 
					 * @origin: the original mount from where the tree walk initiated
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct vfsmount *propagation_next(struct vfsmount *m,
 | 
				
			||||||
 | 
										 struct vfsmount *origin)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						m = next_peer(m);
 | 
				
			||||||
 | 
						if (m == origin)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						return m;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * mount 'source_mnt' under the destination 'dest_mnt' at
 | 
				
			||||||
 | 
					 * dentry 'dest_dentry'. And propagate that mount to
 | 
				
			||||||
 | 
					 * all the peer and slave mounts of 'dest_mnt'.
 | 
				
			||||||
 | 
					 * Link all the new mounts into a propagation tree headed at
 | 
				
			||||||
 | 
					 * source_mnt. Also link all the new mounts using ->mnt_list
 | 
				
			||||||
 | 
					 * headed at source_mnt's ->mnt_list
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @dest_mnt: destination mount.
 | 
				
			||||||
 | 
					 * @dest_dentry: destination dentry.
 | 
				
			||||||
 | 
					 * @source_mnt: source mount.
 | 
				
			||||||
 | 
					 * @tree_list : list of heads of trees to be attached.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int propagate_mnt(struct vfsmount *dest_mnt, struct dentry *dest_dentry,
 | 
				
			||||||
 | 
							    struct vfsmount *source_mnt, struct list_head *tree_list)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct vfsmount *m, *child;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
						struct vfsmount *prev_dest_mnt = dest_mnt;
 | 
				
			||||||
 | 
						struct vfsmount *prev_src_mnt  = source_mnt;
 | 
				
			||||||
 | 
						LIST_HEAD(tmp_list);
 | 
				
			||||||
 | 
						LIST_HEAD(umount_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (m = propagation_next(dest_mnt, dest_mnt); m;
 | 
				
			||||||
 | 
								m = propagation_next(m, dest_mnt)) {
 | 
				
			||||||
 | 
							int type = CL_PROPAGATION;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (IS_MNT_NEW(m))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (IS_MNT_SHARED(m))
 | 
				
			||||||
 | 
								type |= CL_MAKE_SHARED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!(child = copy_tree(source_mnt, source_mnt->mnt_root,
 | 
				
			||||||
 | 
											type))) {
 | 
				
			||||||
 | 
								ret = -ENOMEM;
 | 
				
			||||||
 | 
								list_splice(tree_list, tmp_list.prev);
 | 
				
			||||||
 | 
								goto out;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (is_subdir(dest_dentry, m->mnt_root)) {
 | 
				
			||||||
 | 
								mnt_set_mountpoint(m, dest_dentry, child);
 | 
				
			||||||
 | 
								list_add_tail(&child->mnt_hash, tree_list);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * This can happen if the parent mount was bind mounted
 | 
				
			||||||
 | 
								 * on some subdirectory of a shared/slave mount.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								list_add_tail(&child->mnt_hash, &tmp_list);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							prev_dest_mnt = m;
 | 
				
			||||||
 | 
							prev_src_mnt  = child;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						spin_lock(&vfsmount_lock);
 | 
				
			||||||
 | 
						while (!list_empty(&tmp_list)) {
 | 
				
			||||||
 | 
							child = list_entry(tmp_list.next, struct vfsmount, mnt_hash);
 | 
				
			||||||
 | 
							list_del_init(&child->mnt_hash);
 | 
				
			||||||
 | 
							umount_tree(child, &umount_list);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						spin_unlock(&vfsmount_lock);
 | 
				
			||||||
 | 
						release_mounts(&umount_list);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										14
									
								
								fs/pnode.h
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								fs/pnode.h
									
									
									
									
									
								
							| 
						 | 
					@ -12,7 +12,21 @@
 | 
				
			||||||
#include <linux/mount.h>
 | 
					#include <linux/mount.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define IS_MNT_SHARED(mnt) (mnt->mnt_flags & MNT_SHARED)
 | 
					#define IS_MNT_SHARED(mnt) (mnt->mnt_flags & MNT_SHARED)
 | 
				
			||||||
 | 
					#define IS_MNT_NEW(mnt)  (!mnt->mnt_namespace)
 | 
				
			||||||
#define CLEAR_MNT_SHARED(mnt) (mnt->mnt_flags &= ~MNT_SHARED)
 | 
					#define CLEAR_MNT_SHARED(mnt) (mnt->mnt_flags &= ~MNT_SHARED)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CL_EXPIRE    		0x01
 | 
				
			||||||
 | 
					#define CL_COPY_ALL 		0x04
 | 
				
			||||||
 | 
					#define CL_MAKE_SHARED 		0x08
 | 
				
			||||||
 | 
					#define CL_PROPAGATION 		0x10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void set_mnt_shared(struct vfsmount *mnt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						mnt->mnt_flags &= ~MNT_PNODE_MASK;
 | 
				
			||||||
 | 
						mnt->mnt_flags |= MNT_SHARED;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void change_mnt_propagation(struct vfsmount *, int);
 | 
					void change_mnt_propagation(struct vfsmount *, int);
 | 
				
			||||||
 | 
					int propagate_mnt(struct vfsmount *, struct dentry *, struct vfsmount *,
 | 
				
			||||||
 | 
							struct list_head *);
 | 
				
			||||||
#endif /* _LINUX_PNODE_H */
 | 
					#endif /* _LINUX_PNODE_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1251,7 +1251,12 @@ extern int unregister_filesystem(struct file_system_type *);
 | 
				
			||||||
extern struct vfsmount *kern_mount(struct file_system_type *);
 | 
					extern struct vfsmount *kern_mount(struct file_system_type *);
 | 
				
			||||||
extern int may_umount_tree(struct vfsmount *);
 | 
					extern int may_umount_tree(struct vfsmount *);
 | 
				
			||||||
extern int may_umount(struct vfsmount *);
 | 
					extern int may_umount(struct vfsmount *);
 | 
				
			||||||
 | 
					extern void umount_tree(struct vfsmount *, struct list_head *);
 | 
				
			||||||
 | 
					extern void release_mounts(struct list_head *);
 | 
				
			||||||
extern long do_mount(char *, char *, char *, unsigned long, void *);
 | 
					extern long do_mount(char *, char *, char *, unsigned long, void *);
 | 
				
			||||||
 | 
					extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int);
 | 
				
			||||||
 | 
					extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *,
 | 
				
			||||||
 | 
									  struct vfsmount *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int vfs_statfs(struct super_block *, struct kstatfs *);
 | 
					extern int vfs_statfs(struct super_block *, struct kstatfs *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue