All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ram Pai <linuxram@us.ibm.com>
To: akpm@osdl.org, Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
Cc: Avantika Mathur <mathurav@us.ibm.com>,
	Mike Waychison <mike@waychison.com>
Date: Mon, 25 Jul 2005 15:44:21 -0700	[thread overview]
raw)
In-Reply-To: 20050725224417.501066000@localhost

, miklos@szeredi.hu, Janak Desai <janak@us.ibm.com>, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 4/7] shared subtree
Content-Type: text/x-patch; name=move.patch
Content-Disposition: inline; filename=move.patch

Adds ability to move a shared/private/slave/unclone tree to any other
shared/private/slave/unclone tree. Also incorporates the same behavior
for pivot_root()

RP


Signed by Ram Pai (linuxram@us.ibm.com)

 fs/namespace.c        |  196 +++++++++++++++++++++++++++++++++++++++++++-------
 include/linux/mount.h |    2 
 2 files changed, 173 insertions(+), 25 deletions(-)

Index: 2.6.12.work2/fs/namespace.c
===================================================================
--- 2.6.12.work2.orig/fs/namespace.c
+++ 2.6.12.work2/fs/namespace.c
@@ -772,9 +772,12 @@ static void abort_attach_recursive_mnt(s
 	list_del_init(head);
 }
 
+
  /*
  *  @source_mnt : mount tree to be attached
  *  @nd		: place the mount tree @source_mnt is attached
+ *  @move	: use the move semantics if set, else use normal attach semantics
+ *                as explained below
  *
  *  NOTE: in the table below explains the semantics when a source vfsmount
  *  of a given type is attached to a destination vfsmount of a give type.
@@ -801,12 +804,41 @@ static void abort_attach_recursive_mnt(s
  *  |		|		|       	 |   	    |    	|
  *   ********************************************************************
  *
- * (++)  the mount will be propogated to all the vfsmounts in the pnode tree
+ * (++)  the mount is propogated to all the vfsmounts in the pnode tree
  *    	  of the destination vfsmount, and all the non-slave new mounts in
  *    	  destination vfsmount will be added the source vfsmount's pnode.
- * (+)  the mount will be propogated to the destination vfsmount
+ * (+)  the mount is propogated to the destination vfsmount
  *    	  and the new mount will be added to the source vfsmount's pnode.
  *
+ *  ---------------------------------------------------------------------
+ *  |				MOVE MOUNT OPERATION			|
+ *  |*******************************************************************|
+ *  |  dest --> | shared	|	private	 |  slave   |unclonable	|
+ *  | source	|		|       	 |   	    |    	|
+ *  |   |   	|		|       	 |   	    |    	|
+ *  |   v 	|		|       	 |   	    |    	|
+ *  |*******************************************************************|
+ *  |	     	|		|       	 |   	    |    	|
+ *  |  shared	| shared (++) 	|      shared (+)|shared (+)| shared (+)|
+ *  |		|		|       	 |   	    |    	|
+ *  |		|		|       	 |   	    |    	|
+ *  | private	| shared (+)	|      private	 | private  | private  	|
+ *  |		|		|       	 |   	    |    	|
+ *  |		|		|       	 |   	    |    	|
+ *  | slave	| shared (+++)	|      slave     | slave    | slave  	|
+ *  |		|		|       	 |   	    |    	|
+ *  |		|		|       	 |   	    |    	|
+ *  | unclonable|  invalid	|     unclonable |unclonable| unclonable|
+ *  |		|		|       	 |   	    |    	|
+ *  |		|		|       	 |   	    |    	|
+ *   ********************************************************************
+ *
+ * (+++)  the mount is propogated to all the vfsmounts in the pnode tree
+ *    	  of the destination vfsmount, and all the new mounts is
+ *    	  added to a new pnode , which is a slave pnode of the
+ *    	  source vfsmount's pnode.
+ *
+ *
  * if the source mount is a tree, the operations explained above is
  * applied to each vfsmount in the tree.
  *
@@ -815,7 +847,7 @@ static void abort_attach_recursive_mnt(s
  *
   */
 static int attach_recursive_mnt(struct vfsmount *source_mnt,
-		struct nameidata *nd)
+		struct nameidata *nd, int move)
 {
 	struct vfsmount *mntpt_mnt, *last, *m, *p;
 	struct vfspnode *src_pnode, *dest_pnode, *tmp_pnode;
@@ -849,8 +881,8 @@ static int attach_recursive_mnt(struct v
 	list_add_tail(&mnt_list_head, &source_mnt->mnt_list);
 
 	for (m = source_mnt; m; m = next_mnt(m, source_mnt)) {
-
-		BUG_ON(IS_MNT_UNCLONE(m));
+		int unclone = IS_MNT_UNCLONE(m);
+		int slave = IS_MNT_SLAVE(m);
 
 		while (p && p != m->mnt_parent)
 			p = p->mnt_parent;
@@ -866,7 +898,7 @@ static int attach_recursive_mnt(struct v
 
 		dest_pnode = IS_MNT_SHARED(mntpt_mnt) ?
 			mntpt_mnt->mnt_pnode : NULL;
-		src_pnode = (IS_MNT_SHARED(m))?
+		src_pnode = (IS_MNT_SHARED(m) || (move && slave))?
 				m->mnt_pnode : NULL;
 
 		/*
@@ -882,7 +914,7 @@ static int attach_recursive_mnt(struct v
 		list_del_init(&m->mnt_list);
 		list_add_tail(&tmp_pnode->pnode_peer_slave, &pnodehead);
 
-		if (dest_pnode) {
+		if (dest_pnode && !unclone) {
 			if ((ret = pnode_prepare_mount(dest_pnode, tmp_pnode,
 					mntpt_dentry, m, mntpt_mnt))) {
 				tmp_pnode->pnode_master = src_pnode;
@@ -890,23 +922,33 @@ static int attach_recursive_mnt(struct v
 				last = m;
 				goto error;
 			}
+			if (move && dest_pnode && slave)
+ 				SET_PNODE_SLAVE(tmp_pnode);
 		} else {
 			if (m == m->mnt_parent)
 				do_attach_prepare_mnt(mntpt_mnt,
 					mntpt_dentry, m, 0);
-			pnode_add_member_mnt(tmp_pnode, m);
-			if (!src_pnode) {
-				set_mnt_private(m);
+			if (move && slave)
+				pnode_add_slave_mnt(tmp_pnode, m);
+			else {
+				pnode_add_member_mnt(tmp_pnode, m);
+				if (unclone) {
+					BUG_ON(!move);
+					set_mnt_unclone(m);
+					m->mnt_pnode = tmp_pnode;
+					SET_PNODE_DELETE(tmp_pnode);
+				} else if (!src_pnode) {
+					set_mnt_private(m);
+					m->mnt_pnode = tmp_pnode;
+					SET_PNODE_DELETE(tmp_pnode);
+				}
 				/*
-				 * NOTE: set_mnt_private()
-				 * resets m->mnt_pnode.
-				 * Reinitialize it. This is needed to
-				 * decrement the refcount on the
-				 * pnode when the mount 'm' is
-				 * unlinked in pnode_commit_mount().
+				 * NOTE: set_mnt_private() & set_mnt_unclone()
+				 * resets m->mnt_pnode. Hence reinitialize it.
+				 * We need this to decrement the refcount
+				 * on the pnode when the mount 'm' is
+				 * unlinked in pnode_commit_mount()
 				 */
-				m->mnt_pnode = tmp_pnode;
-				SET_PNODE_DELETE(tmp_pnode);
 			}
 		}
 
@@ -931,6 +973,46 @@ error:
 	return 1;
 }
 
+static void
+detach_recursive_mnt(struct vfsmount *source_mnt, struct nameidata *nd)
+{
+	struct vfsmount *m;
+
+	detach_mnt(source_mnt, nd);
+	spin_lock(&vfspnode_lock);
+	for (m = source_mnt; m; m = next_mnt(m, source_mnt)) {
+		list_del_init(&m->mnt_pnode_mntlist);
+		list_del_init(&m->mnt_list);
+		if (m != source_mnt)
+			list_add_tail(&m->mnt_list, &source_mnt->mnt_list);
+	}
+	spin_unlock(&vfspnode_lock);
+}
+
+static void
+undo_detach_recursive_mnt(struct vfsmount *mnt, struct nameidata *nd)
+{
+	struct vfsmount *m;
+	LIST_HEAD(head);
+
+	spin_lock(&vfspnode_lock);
+	for (m = mnt; m; m = next_mnt(m, mnt)) {
+		if (m->mnt_pnode) {
+			if (IS_MNT_SHARED(m))
+				list_add(&m->mnt_pnode_mntlist,
+					&m->mnt_pnode->pnode_vfs);
+			if (IS_MNT_SLAVE(m))
+				list_add(&m->mnt_pnode_mntlist,
+					&m->mnt_pnode->pnode_slavevfs);
+		}
+	}
+	attach_mnt(mnt, nd);
+	spin_unlock(&vfspnode_lock);
+
+	list_add_tail(&head, &mnt->mnt_list);
+	list_splice(&head, nd->mnt->mnt_namespace->list.prev);
+}
+
 static int graft_tree(struct vfsmount *mnt, struct nameidata *nd)
 {
 	int err, ret;
@@ -957,7 +1039,7 @@ static int graft_tree(struct vfsmount *m
 	ret = (IS_ROOT(nd->dentry) || !d_unhashed(nd->dentry));
 	spin_unlock(&vfsmount_lock);
 	if (ret)
-		err = attach_recursive_mnt(mnt, nd);
+		err = attach_recursive_mnt(mnt, nd, 0);
 out_unlock:
 	up(&nd->dentry->d_inode->i_sem);
 	if (!err)
@@ -1311,6 +1393,19 @@ static int do_remount(struct nameidata *
 	return err;
 }
 
+/*
+ * return 1 if the mount tree contains a unclonable mount
+ */
+static inline int tree_contains_unclone(struct vfsmount *mnt)
+{
+	struct vfsmount *p;
+	for (p = mnt; p; p = next_mnt(p, mnt)) {
+		if (IS_MNT_UNCLONE(p))
+			return 1;
+	}
+	return 0;
+}
+
 static int do_move_mount(struct nameidata *nd, char *old_name)
 {
 	struct nameidata old_nd, parent_nd;
@@ -1351,14 +1446,35 @@ static int do_move_mount(struct nameidat
 	      S_ISDIR(old_nd.dentry->d_inode->i_mode))
 		goto out2;
 
+	/*
+	 * Don't move a mount in a shared parent.
+	 */
+	if (old_nd.mnt->mnt_parent &&
+		IS_MNT_SHARED(old_nd.mnt->mnt_parent))
+		goto out2;
+
+	/*
+	 * Don't move a mount tree having unclonable
+	 * mounts, under a shared mount
+	 */
+	if (IS_MNT_SHARED(nd->mnt) &&
+		tree_contains_unclone(old_nd.mnt))
+		goto out2;
+
 	err = -ELOOP;
 	for (p = nd->mnt; p->mnt_parent!=p; p = p->mnt_parent)
 		if (p == old_nd.mnt)
 			goto out2;
 	err = 0;
 
-	detach_mnt(old_nd.mnt, &parent_nd);
-	attach_mnt(old_nd.mnt, nd);
+	detach_recursive_mnt(old_nd.mnt, &parent_nd);
+	spin_unlock(&vfsmount_lock);
+	if ((err = attach_recursive_mnt(old_nd.mnt, nd, 1))) {
+		undo_detach_recursive_mnt(old_nd.mnt, &parent_nd);
+		goto out1;
+	}
+	spin_lock(&vfsmount_lock);
+	mntput(old_nd.mnt);
 
 	/* if the mount is moved, it should no longer be expire
 	 * automatically */
@@ -1949,6 +2065,16 @@ asmlinkage long sys_pivot_root(const cha
 		goto out2; /* not a mountpoint */
 	if (new_nd.mnt->mnt_root != new_nd.dentry)
 		goto out2; /* not a mountpoint */
+	/*
+	 * Don't move a mount in a shared parent.
+	 */
+	if(user_nd.mnt->mnt_parent &&
+		IS_MNT_SHARED(user_nd.mnt->mnt_parent))
+		goto out2;
+	if(new_nd.mnt->mnt_parent &&
+		IS_MNT_SHARED(new_nd.mnt->mnt_parent))
+		goto out2;
+
 	tmp = old_nd.mnt; /* make sure we can reach put_old from new_root */
 	spin_lock(&vfsmount_lock);
 	if (tmp != new_nd.mnt) {
@@ -1963,10 +2089,30 @@ asmlinkage long sys_pivot_root(const cha
 			goto out3;
 	} else if (!is_subdir(old_nd.dentry, new_nd.dentry))
 		goto out3;
-	detach_mnt(new_nd.mnt, &parent_nd);
-	detach_mnt(user_nd.mnt, &root_parent);
-	attach_mnt(user_nd.mnt, &old_nd);     /* mount old root on put_old */
-	attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */
+
+	detach_recursive_mnt(user_nd.mnt, &root_parent);
+	detach_recursive_mnt(new_nd.mnt, &parent_nd);
+
+	spin_unlock(&vfsmount_lock);
+ 	if ((error = attach_recursive_mnt(user_nd.mnt, &old_nd, 1))) {
+		spin_lock(&vfsmount_lock);
+		undo_detach_recursive_mnt(new_nd.mnt, &parent_nd);
+		undo_detach_recursive_mnt(user_nd.mnt, &root_parent);
+		goto out3;
+	}
+	spin_lock(&vfsmount_lock);
+ 	mntput(user_nd.mnt);
+
+	spin_unlock(&vfsmount_lock);
+ 	if ((error = attach_recursive_mnt(new_nd.mnt, &root_parent, 1))) {
+		spin_lock(&vfsmount_lock);
+		undo_detach_recursive_mnt(new_nd.mnt, &parent_nd);
+		undo_detach_recursive_mnt(user_nd.mnt, &root_parent);
+		goto out3;
+	}
+	spin_lock(&vfsmount_lock);
+ 	mntput(new_nd.mnt);
+
 	spin_unlock(&vfsmount_lock);
 	chroot_fs_refs(&user_nd, &new_nd);
 	security_sb_post_pivotroot(&user_nd, &new_nd);
Index: 2.6.12.work2/include/linux/mount.h
===================================================================
--- 2.6.12.work2.orig/include/linux/mount.h
+++ 2.6.12.work2/include/linux/mount.h
@@ -29,6 +29,8 @@
 #define IS_MNT_SLAVE(mnt) (mnt->mnt_flags & MNT_SLAVE)
 #define IS_MNT_PRIVATE(mnt) (mnt->mnt_flags & MNT_PRIVATE)
 #define IS_MNT_UNCLONE(mnt) (mnt->mnt_flags & MNT_UNCLONE)
+#define GET_MNT_TYPE(mnt) (mnt->mnt_flags & MNT_PNODE_MASK)
+#define SET_MNT_TYPE(mnt, type) (mnt->mnt_flags |= (type & MNT_PNODE_MASK))
 
 #define CLEAR_MNT_SHARED(mnt) (mnt->mnt_flags &= ~(MNT_PNODE_MASK & MNT_SHARED))
 #define CLEAR_MNT_PRIVATE(mnt) (mnt->mnt_flags &= ~(MNT_PNODE_MASK & MNT_PRIVATE))

WARNING: multiple messages have this Message-ID (diff)
From: Ram Pai <linuxram@us.ibm.com>
To: akpm@osdl.org, Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
Cc: Avantika Mathur <mathurav@us.ibm.com>,
	Mike Waychison <mike@waychison.com>
Subject: (unknown)
Date: Mon, 25 Jul 2005 15:44:21 -0700	[thread overview]
Message-ID: <20050725225908.220780000@localhost> (raw)
In-Reply-To: 20050725224417.501066000@localhost

, miklos@szeredi.hu, Janak Desai <janak@us.ibm.com>, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 4/7] shared subtree
Content-Type: text/x-patch; name=move.patch
Content-Disposition: inline; filename=move.patch

Adds ability to move a shared/private/slave/unclone tree to any other
shared/private/slave/unclone tree. Also incorporates the same behavior
for pivot_root()

RP


Signed by Ram Pai (linuxram@us.ibm.com)

 fs/namespace.c        |  196 +++++++++++++++++++++++++++++++++++++++++++-------
 include/linux/mount.h |    2 
 2 files changed, 173 insertions(+), 25 deletions(-)

Index: 2.6.12.work2/fs/namespace.c
===================================================================
--- 2.6.12.work2.orig/fs/namespace.c
+++ 2.6.12.work2/fs/namespace.c
@@ -772,9 +772,12 @@ static void abort_attach_recursive_mnt(s
 	list_del_init(head);
 }
 
+
  /*
  *  @source_mnt : mount tree to be attached
  *  @nd		: place the mount tree @source_mnt is attached
+ *  @move	: use the move semantics if set, else use normal attach semantics
+ *                as explained below
  *
  *  NOTE: in the table below explains the semantics when a source vfsmount
  *  of a given type is attached to a destination vfsmount of a give type.
@@ -801,12 +804,41 @@ static void abort_attach_recursive_mnt(s
  *  |		|		|       	 |   	    |    	|
  *   ********************************************************************
  *
- * (++)  the mount will be propogated to all the vfsmounts in the pnode tree
+ * (++)  the mount is propogated to all the vfsmounts in the pnode tree
  *    	  of the destination vfsmount, and all the non-slave new mounts in
  *    	  destination vfsmount will be added the source vfsmount's pnode.
- * (+)  the mount will be propogated to the destination vfsmount
+ * (+)  the mount is propogated to the destination vfsmount
  *    	  and the new mount will be added to the source vfsmount's pnode.
  *
+ *  ---------------------------------------------------------------------
+ *  |				MOVE MOUNT OPERATION			|
+ *  |*******************************************************************|
+ *  |  dest --> | shared	|	private	 |  slave   |unclonable	|
+ *  | source	|		|       	 |   	    |    	|
+ *  |   |   	|		|       	 |   	    |    	|
+ *  |   v 	|		|       	 |   	    |    	|
+ *  |*******************************************************************|
+ *  |	     	|		|       	 |   	    |    	|
+ *  |  shared	| shared (++) 	|      shared (+)|shared (+)| shared (+)|
+ *  |		|		|       	 |   	    |    	|
+ *  |		|		|       	 |   	    |    	|
+ *  | private	| shared (+)	|      private	 | private  | private  	|
+ *  |		|		|       	 |   	    |    	|
+ *  |		|		|       	 |   	    |    	|
+ *  | slave	| shared (+++)	|      slave     | slave    | slave  	|
+ *  |		|		|       	 |   	    |    	|
+ *  |		|		|       	 |   	    |    	|
+ *  | unclonable|  invalid	|     unclonable |unclonable| unclonable|
+ *  |		|		|       	 |   	    |    	|
+ *  |		|		|       	 |   	    |    	|
+ *   ********************************************************************
+ *
+ * (+++)  the mount is propogated to all the vfsmounts in the pnode tree
+ *    	  of the destination vfsmount, and all the new mounts is
+ *    	  added to a new pnode , which is a slave pnode of the
+ *    	  source vfsmount's pnode.
+ *
+ *
  * if the source mount is a tree, the operations explained above is
  * applied to each vfsmount in the tree.
  *
@@ -815,7 +847,7 @@ static void abort_attach_recursive_mnt(s
  *
   */
 static int attach_recursive_mnt(struct vfsmount *source_mnt,
-		struct nameidata *nd)
+		struct nameidata *nd, int move)
 {
 	struct vfsmount *mntpt_mnt, *last, *m, *p;
 	struct vfspnode *src_pnode, *dest_pnode, *tmp_pnode;
@@ -849,8 +881,8 @@ static int attach_recursive_mnt(struct v
 	list_add_tail(&mnt_list_head, &source_mnt->mnt_list);
 
 	for (m = source_mnt; m; m = next_mnt(m, source_mnt)) {
-
-		BUG_ON(IS_MNT_UNCLONE(m));
+		int unclone = IS_MNT_UNCLONE(m);
+		int slave = IS_MNT_SLAVE(m);
 
 		while (p && p != m->mnt_parent)
 			p = p->mnt_parent;
@@ -866,7 +898,7 @@ static int attach_recursive_mnt(struct v
 
 		dest_pnode = IS_MNT_SHARED(mntpt_mnt) ?
 			mntpt_mnt->mnt_pnode : NULL;
-		src_pnode = (IS_MNT_SHARED(m))?
+		src_pnode = (IS_MNT_SHARED(m) || (move && slave))?
 				m->mnt_pnode : NULL;
 
 		/*
@@ -882,7 +914,7 @@ static int attach_recursive_mnt(struct v
 		list_del_init(&m->mnt_list);
 		list_add_tail(&tmp_pnode->pnode_peer_slave, &pnodehead);
 
-		if (dest_pnode) {
+		if (dest_pnode && !unclone) {
 			if ((ret = pnode_prepare_mount(dest_pnode, tmp_pnode,
 					mntpt_dentry, m, mntpt_mnt))) {
 				tmp_pnode->pnode_master = src_pnode;
@@ -890,23 +922,33 @@ static int attach_recursive_mnt(struct v
 				last = m;
 				goto error;
 			}
+			if (move && dest_pnode && slave)
+ 				SET_PNODE_SLAVE(tmp_pnode);
 		} else {
 			if (m == m->mnt_parent)
 				do_attach_prepare_mnt(mntpt_mnt,
 					mntpt_dentry, m, 0);
-			pnode_add_member_mnt(tmp_pnode, m);
-			if (!src_pnode) {
-				set_mnt_private(m);
+			if (move && slave)
+				pnode_add_slave_mnt(tmp_pnode, m);
+			else {
+				pnode_add_member_mnt(tmp_pnode, m);
+				if (unclone) {
+					BUG_ON(!move);
+					set_mnt_unclone(m);
+					m->mnt_pnode = tmp_pnode;
+					SET_PNODE_DELETE(tmp_pnode);
+				} else if (!src_pnode) {
+					set_mnt_private(m);
+					m->mnt_pnode = tmp_pnode;
+					SET_PNODE_DELETE(tmp_pnode);
+				}
 				/*
-				 * NOTE: set_mnt_private()
-				 * resets m->mnt_pnode.
-				 * Reinitialize it. This is needed to
-				 * decrement the refcount on the
-				 * pnode when the mount 'm' is
-				 * unlinked in pnode_commit_mount().
+				 * NOTE: set_mnt_private() & set_mnt_unclone()
+				 * resets m->mnt_pnode. Hence reinitialize it.
+				 * We need this to decrement the refcount
+				 * on the pnode when the mount 'm' is
+				 * unlinked in pnode_commit_mount()
 				 */
-				m->mnt_pnode = tmp_pnode;
-				SET_PNODE_DELETE(tmp_pnode);
 			}
 		}
 
@@ -931,6 +973,46 @@ error:
 	return 1;
 }
 
+static void
+detach_recursive_mnt(struct vfsmount *source_mnt, struct nameidata *nd)
+{
+	struct vfsmount *m;
+
+	detach_mnt(source_mnt, nd);
+	spin_lock(&vfspnode_lock);
+	for (m = source_mnt; m; m = next_mnt(m, source_mnt)) {
+		list_del_init(&m->mnt_pnode_mntlist);
+		list_del_init(&m->mnt_list);
+		if (m != source_mnt)
+			list_add_tail(&m->mnt_list, &source_mnt->mnt_list);
+	}
+	spin_unlock(&vfspnode_lock);
+}
+
+static void
+undo_detach_recursive_mnt(struct vfsmount *mnt, struct nameidata *nd)
+{
+	struct vfsmount *m;
+	LIST_HEAD(head);
+
+	spin_lock(&vfspnode_lock);
+	for (m = mnt; m; m = next_mnt(m, mnt)) {
+		if (m->mnt_pnode) {
+			if (IS_MNT_SHARED(m))
+				list_add(&m->mnt_pnode_mntlist,
+					&m->mnt_pnode->pnode_vfs);
+			if (IS_MNT_SLAVE(m))
+				list_add(&m->mnt_pnode_mntlist,
+					&m->mnt_pnode->pnode_slavevfs);
+		}
+	}
+	attach_mnt(mnt, nd);
+	spin_unlock(&vfspnode_lock);
+
+	list_add_tail(&head, &mnt->mnt_list);
+	list_splice(&head, nd->mnt->mnt_namespace->list.prev);
+}
+
 static int graft_tree(struct vfsmount *mnt, struct nameidata *nd)
 {
 	int err, ret;
@@ -957,7 +1039,7 @@ static int graft_tree(struct vfsmount *m
 	ret = (IS_ROOT(nd->dentry) || !d_unhashed(nd->dentry));
 	spin_unlock(&vfsmount_lock);
 	if (ret)
-		err = attach_recursive_mnt(mnt, nd);
+		err = attach_recursive_mnt(mnt, nd, 0);
 out_unlock:
 	up(&nd->dentry->d_inode->i_sem);
 	if (!err)
@@ -1311,6 +1393,19 @@ static int do_remount(struct nameidata *
 	return err;
 }
 
+/*
+ * return 1 if the mount tree contains a unclonable mount
+ */
+static inline int tree_contains_unclone(struct vfsmount *mnt)
+{
+	struct vfsmount *p;
+	for (p = mnt; p; p = next_mnt(p, mnt)) {
+		if (IS_MNT_UNCLONE(p))
+			return 1;
+	}
+	return 0;
+}
+
 static int do_move_mount(struct nameidata *nd, char *old_name)
 {
 	struct nameidata old_nd, parent_nd;
@@ -1351,14 +1446,35 @@ static int do_move_mount(struct nameidat
 	      S_ISDIR(old_nd.dentry->d_inode->i_mode))
 		goto out2;
 
+	/*
+	 * Don't move a mount in a shared parent.
+	 */
+	if (old_nd.mnt->mnt_parent &&
+		IS_MNT_SHARED(old_nd.mnt->mnt_parent))
+		goto out2;
+
+	/*
+	 * Don't move a mount tree having unclonable
+	 * mounts, under a shared mount
+	 */
+	if (IS_MNT_SHARED(nd->mnt) &&
+		tree_contains_unclone(old_nd.mnt))
+		goto out2;
+
 	err = -ELOOP;
 	for (p = nd->mnt; p->mnt_parent!=p; p = p->mnt_parent)
 		if (p == old_nd.mnt)
 			goto out2;
 	err = 0;
 
-	detach_mnt(old_nd.mnt, &parent_nd);
-	attach_mnt(old_nd.mnt, nd);
+	detach_recursive_mnt(old_nd.mnt, &parent_nd);
+	spin_unlock(&vfsmount_lock);
+	if ((err = attach_recursive_mnt(old_nd.mnt, nd, 1))) {
+		undo_detach_recursive_mnt(old_nd.mnt, &parent_nd);
+		goto out1;
+	}
+	spin_lock(&vfsmount_lock);
+	mntput(old_nd.mnt);
 
 	/* if the mount is moved, it should no longer be expire
 	 * automatically */
@@ -1949,6 +2065,16 @@ asmlinkage long sys_pivot_root(const cha
 		goto out2; /* not a mountpoint */
 	if (new_nd.mnt->mnt_root != new_nd.dentry)
 		goto out2; /* not a mountpoint */
+	/*
+	 * Don't move a mount in a shared parent.
+	 */
+	if(user_nd.mnt->mnt_parent &&
+		IS_MNT_SHARED(user_nd.mnt->mnt_parent))
+		goto out2;
+	if(new_nd.mnt->mnt_parent &&
+		IS_MNT_SHARED(new_nd.mnt->mnt_parent))
+		goto out2;
+
 	tmp = old_nd.mnt; /* make sure we can reach put_old from new_root */
 	spin_lock(&vfsmount_lock);
 	if (tmp != new_nd.mnt) {
@@ -1963,10 +2089,30 @@ asmlinkage long sys_pivot_root(const cha
 			goto out3;
 	} else if (!is_subdir(old_nd.dentry, new_nd.dentry))
 		goto out3;
-	detach_mnt(new_nd.mnt, &parent_nd);
-	detach_mnt(user_nd.mnt, &root_parent);
-	attach_mnt(user_nd.mnt, &old_nd);     /* mount old root on put_old */
-	attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */
+
+	detach_recursive_mnt(user_nd.mnt, &root_parent);
+	detach_recursive_mnt(new_nd.mnt, &parent_nd);
+
+	spin_unlock(&vfsmount_lock);
+ 	if ((error = attach_recursive_mnt(user_nd.mnt, &old_nd, 1))) {
+		spin_lock(&vfsmount_lock);
+		undo_detach_recursive_mnt(new_nd.mnt, &parent_nd);
+		undo_detach_recursive_mnt(user_nd.mnt, &root_parent);
+		goto out3;
+	}
+	spin_lock(&vfsmount_lock);
+ 	mntput(user_nd.mnt);
+
+	spin_unlock(&vfsmount_lock);
+ 	if ((error = attach_recursive_mnt(new_nd.mnt, &root_parent, 1))) {
+		spin_lock(&vfsmount_lock);
+		undo_detach_recursive_mnt(new_nd.mnt, &parent_nd);
+		undo_detach_recursive_mnt(user_nd.mnt, &root_parent);
+		goto out3;
+	}
+	spin_lock(&vfsmount_lock);
+ 	mntput(new_nd.mnt);
+
 	spin_unlock(&vfsmount_lock);
 	chroot_fs_refs(&user_nd, &new_nd);
 	security_sb_post_pivotroot(&user_nd, &new_nd);
Index: 2.6.12.work2/include/linux/mount.h
===================================================================
--- 2.6.12.work2.orig/include/linux/mount.h
+++ 2.6.12.work2/include/linux/mount.h
@@ -29,6 +29,8 @@
 #define IS_MNT_SLAVE(mnt) (mnt->mnt_flags & MNT_SLAVE)
 #define IS_MNT_PRIVATE(mnt) (mnt->mnt_flags & MNT_PRIVATE)
 #define IS_MNT_UNCLONE(mnt) (mnt->mnt_flags & MNT_UNCLONE)
+#define GET_MNT_TYPE(mnt) (mnt->mnt_flags & MNT_PNODE_MASK)
+#define SET_MNT_TYPE(mnt, type) (mnt->mnt_flags |= (type & MNT_PNODE_MASK))
 
 #define CLEAR_MNT_SHARED(mnt) (mnt->mnt_flags &= ~(MNT_PNODE_MASK & MNT_SHARED))
 #define CLEAR_MNT_PRIVATE(mnt) (mnt->mnt_flags &= ~(MNT_PNODE_MASK & MNT_PRIVATE))

  parent reply	other threads:[~2005-07-25 22:59 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-07-25 22:44 Ram Pai
2005-07-25 22:44 ` (unknown) Ram Pai
2005-07-25 22:44 ` Ram Pai
2005-07-27 19:54   ` [PATCH 1/7] shared subtree Miklos Szeredi
2005-07-27 21:39     ` Ram Pai
2005-07-28  7:35       ` mount behavior question Ram Pai
2005-07-28 11:56         ` Miklos Szeredi
2005-07-28 15:02           ` Ram Pai
2005-07-28 15:58             ` Miklos Szeredi
2005-07-28 18:22               ` Ram Pai
2005-07-28 19:30                 ` Miklos Szeredi
2005-07-28 20:09                   ` Ram Pai
2005-07-28 20:44                     ` Miklos Szeredi
2005-07-28 20:59                       ` Ram Pai
2005-07-28 18:27         ` Bryan Henderson
2005-07-28 19:01           ` Miklos Szeredi
2005-07-28 20:35             ` Bryan Henderson
2005-07-28 20:42               ` Ram Pai
2005-07-28 22:27                 ` Bryan Henderson
2005-07-28 22:59                   ` Ram Pai
2005-07-28 20:53               ` Miklos Szeredi
2005-07-28 22:51                 ` Bryan Henderson
2005-07-28  9:57       ` [PATCH 1/7] shared subtree Miklos Szeredi
2005-07-29 19:54         ` Ram Pai
2005-07-30  5:39           ` Miklos Szeredi
2005-07-31  0:45             ` Ram Pai
2005-07-31  7:52               ` Miklos Szeredi
2005-07-31  8:25                 ` Miklos Szeredi
2005-07-25 22:44 ` (unknown) Ram Pai
2005-07-25 22:44 ` Ram Pai
2005-07-25 22:44   ` (unknown) Ram Pai
2005-07-25 22:44 ` (unknown) Ram Pai
2005-07-25 22:44 ` Ram Pai
2005-07-27 19:13   ` [PATCH 3/7] shared subtree Miklos Szeredi
2005-07-27 20:30     ` Ram Pai
2005-07-28  8:34       ` Miklos Szeredi
2005-07-25 22:44 ` Ram Pai [this message]
2005-07-25 22:44   ` (unknown) Ram Pai
2005-07-25 22:44 ` Ram Pai
2005-07-25 22:44   ` (unknown) Ram Pai
2005-07-25 22:44 ` Ram Pai
2005-07-25 22:44 ` (unknown) Ram Pai
2005-07-25 22:44 ` Ram Pai
2005-07-25 22:44   ` (unknown) Ram Pai
2005-07-26  2:53 ` supposed to be shared subtree patches Ram Pai

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20050725225908.220780000@localhost \
    --to=linuxram@us.ibm.com \
    --cc=akpm@osdl.org \
    --cc=mathurav@us.ibm.com \
    --cc=mike@waychison.com \
    --cc=viro@parcelfarce.linux.theplanet.co.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.