, [EMAIL PROTECTED], Janak Desai <[EMAIL PROTECTED]>, 
linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 5/7] shared subtree
Content-Type: text/x-patch; name=umount.patch
Content-Disposition: inline; filename=umount.patch

Adds ability to unmount a shared/slave/unclone/private tree

RP

Signed by Ram Pai ([EMAIL PROTECTED])

 fs/namespace.c        |   76 ++++++++++++++++++++++++++++++++++++++++----------
 fs/pnode.c            |   66 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/fs.h    |    3 +
 include/linux/pnode.h |    9 ++++-
 4 files changed, 138 insertions(+), 16 deletions(-)

Index: 2.6.12.work2/fs/pnode.c
===================================================================
--- 2.6.12.work2.orig/fs/pnode.c
+++ 2.6.12.work2/fs/pnode.c
@@ -666,3 +666,69 @@ int pnode_abort_mount(struct vfspnode *p
                        NULL, (void *)NULL, NULL, NULL,
                        vfs_abort_mount_func, exception_mnt);
 }
+
+static int vfs_busy(struct vfsmount *mnt, enum pnode_vfs_type flag,
+               void *indata, va_list args)
+{
+       struct dentry *dentry = va_arg(args, struct dentry *);
+       struct dentry *rootdentry = va_arg(args, struct dentry *);
+       struct vfsmount *origmnt = va_arg(args, struct vfsmount *);
+       struct vfsmount *child_mnt;
+       int ret=0;
+
+       spin_unlock(&vfsmount_lock);
+       child_mnt = __lookup_mnt(mnt, dentry, rootdentry);
+       spin_lock(&vfsmount_lock);
+
+       if (!child_mnt)
+               return 0;
+
+       if (list_empty(&child_mnt->mnt_mounts)) {
+               if (origmnt == child_mnt)
+                       ret = do_refcount_check(child_mnt, 3);
+               else
+                       ret = do_refcount_check(child_mnt, 2);
+       }
+       mntput(child_mnt);
+       return ret;
+}
+
+int pnode_mount_busy(struct vfspnode *pnode, struct dentry *mntpt,
+               struct dentry *root, struct vfsmount *mnt)
+{
+       return pnode_traverse(pnode, NULL, NULL,
+                       NULL, NULL, vfs_busy, mntpt, root, mnt);
+}
+
+
+int vfs_umount(struct vfsmount *mnt, enum pnode_vfs_type flag,
+               void *indata, va_list args)
+{
+       struct vfsmount *child_mnt;
+       struct dentry *dentry, *rootdentry;
+
+
+       dentry = va_arg(args, struct dentry *);
+       rootdentry = va_arg(args, struct dentry *);
+
+       spin_unlock(&vfsmount_lock);
+       child_mnt = __lookup_mnt(mnt, dentry, rootdentry);
+       spin_lock(&vfsmount_lock);
+       mntput(child_mnt);
+       if (child_mnt && list_empty(&child_mnt->mnt_mounts)) {
+               if (IS_MNT_SHARED(child_mnt) ||
+                               IS_MNT_SLAVE(child_mnt)) {
+                       BUG_ON(!child_mnt->mnt_pnode);
+                       pnode_disassociate_mnt(child_mnt);
+               }
+               do_detach_mount(child_mnt);
+       }
+       return 0;
+}
+
+int pnode_umount(struct vfspnode *pnode, struct dentry *dentry,
+                       struct dentry *rootdentry)
+{
+       return pnode_traverse(pnode, NULL, (void *)NULL,
+                       NULL, NULL, vfs_umount, dentry, rootdentry);
+}
Index: 2.6.12.work2/fs/namespace.c
===================================================================
--- 2.6.12.work2.orig/fs/namespace.c
+++ 2.6.12.work2/fs/namespace.c
@@ -395,6 +395,20 @@ resume:
 
 EXPORT_SYMBOL(may_umount_tree);
 
+int mount_busy(struct vfsmount *mnt)
+{
+       struct vfspnode *parent_pnode;
+
+       if (mnt == mnt->mnt_parent || !IS_MNT_SHARED(mnt->mnt_parent))
+               return do_refcount_check(mnt, 2);
+
+       parent_pnode = mnt->mnt_parent->mnt_pnode;
+       BUG_ON(!parent_pnode);
+       return pnode_mount_busy(parent_pnode,
+                       mnt->mnt_mountpoint,
+                       mnt->mnt_root, mnt);
+}
+
 /**
  * may_umount - check if a mount point is busy
  * @mnt: root of mount
@@ -410,14 +424,28 @@ EXPORT_SYMBOL(may_umount_tree);
  */
 int may_umount(struct vfsmount *mnt)
 {
-       if (atomic_read(&mnt->mnt_count) > 2)
+       if (mount_busy(mnt))
                return -EBUSY;
        return 0;
 }
 
 EXPORT_SYMBOL(may_umount);
 
-void umount_tree(struct vfsmount *mnt)
+void do_detach_mount(struct vfsmount *mnt)
+{
+       struct nameidata old_nd;
+       if (mnt != mnt->mnt_parent) {
+               detach_mnt(mnt, &old_nd);
+               path_release(&old_nd);
+       }
+       list_del_init(&mnt->mnt_list);
+       list_del_init(&mnt->mnt_fslink);
+       spin_unlock(&vfsmount_lock);
+       mntput(mnt);
+       spin_lock(&vfsmount_lock);
+}
+
+void __umount_tree(struct vfsmount *mnt, int propogate)
 {
        struct vfsmount *p;
        LIST_HEAD(kill);
@@ -431,20 +459,40 @@ void umount_tree(struct vfsmount *mnt)
                mnt = list_entry(kill.next, struct vfsmount, mnt_list);
                list_del_init(&mnt->mnt_list);
                list_del_init(&mnt->mnt_fslink);
-               if (mnt->mnt_parent == mnt) {
-                       spin_unlock(&vfsmount_lock);
+               if (propogate && mnt->mnt_parent != mnt &&
+                       IS_MNT_SHARED(mnt->mnt_parent)) {
+                       struct vfspnode *parent_pnode
+                               = mnt->mnt_parent->mnt_pnode;
+                       BUG_ON(!parent_pnode);
+                       pnode_umount(parent_pnode,
+                               mnt->mnt_mountpoint,
+                               mnt->mnt_root);
                } else {
-                       struct nameidata old_nd;
-                       detach_mnt(mnt, &old_nd);
-                       spin_unlock(&vfsmount_lock);
-                       path_release(&old_nd);
+                       if (IS_MNT_SHARED(mnt) || IS_MNT_SLAVE(mnt)) {
+                               BUG_ON(!mnt->mnt_pnode);
+                               pnode_disassociate_mnt(mnt);
+                       }
+                       do_detach_mount(mnt);
                }
-               mntput(mnt);
-               spin_lock(&vfsmount_lock);
        }
 }
 
-static int do_umount(struct vfsmount *mnt, int flags)
+void umount_tree(struct vfsmount *mnt)
+{
+       __umount_tree(mnt, 1);
+}
+
+/*
+ * return true if the refcount is greater than count
+ */
+int do_refcount_check(struct vfsmount *mnt, int count)
+{
+
+       int mycount = atomic_read(&mnt->mnt_count);
+       return (mycount > count);
+}
+
+int do_umount(struct vfsmount *mnt, int flags)
 {
        struct super_block * sb = mnt->mnt_sb;
        int retval;
@@ -525,7 +573,7 @@ static int do_umount(struct vfsmount *mn
                spin_lock(&vfsmount_lock);
        }
        retval = -EBUSY;
-       if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) {
+       if (flags & MNT_DETACH || !mount_busy(mnt)) {
                if (!list_empty(&mnt->mnt_list))
                        umount_tree(mnt);
                retval = 0;
@@ -659,7 +707,7 @@ static struct vfsmount *copy_tree(struct
  Enomem:
        if (res) {
                spin_lock(&vfsmount_lock);
-               umount_tree(res);
+               __umount_tree(res, 0);
                spin_unlock(&vfsmount_lock);
        }
        return NULL;
@@ -1341,7 +1389,7 @@ static int do_loopback(struct nameidata 
                err = graft_tree(mnt, nd);
                if (err) {
                        spin_lock(&vfsmount_lock);
-                       umount_tree(mnt);
+                       __umount_tree(mnt, 0);
                        spin_unlock(&vfsmount_lock);
                        /*
                         * ok we failed! so undo any overlay
Index: 2.6.12.work2/include/linux/fs.h
===================================================================
--- 2.6.12.work2.orig/include/linux/fs.h
+++ 2.6.12.work2/include/linux/fs.h
@@ -1216,12 +1216,15 @@ extern struct vfsmount *kern_mount(struc
 extern int may_umount_tree(struct vfsmount *);
 extern int may_umount(struct vfsmount *);
 extern long do_mount(char *, char *, char *, unsigned long, void *);
+extern int do_umount(struct vfsmount *, int);
 extern struct vfsmount *do_attach_prepare_mnt(struct vfsmount *,
                struct dentry *, struct vfsmount *, int);
 extern void do_attach_commit_mnt(struct vfsmount *);
 extern struct vfsmount *do_make_mounted(struct vfsmount *, struct dentry *);
 extern int do_make_unmounted(struct vfsmount *);
 extern void do_detach_prepare_mnt(struct vfsmount *, int);
+extern void do_detach_mount(struct vfsmount *);
+extern int do_refcount_check(struct vfsmount *, int );
 
 extern int vfs_statfs(struct super_block *, struct kstatfs *);
 
Index: 2.6.12.work2/include/linux/pnode.h
===================================================================
--- 2.6.12.work2.orig/include/linux/pnode.h
+++ 2.6.12.work2/include/linux/pnode.h
@@ -63,13 +63,15 @@ put_pnode_locked(struct vfspnode *pnode)
 {
        if (!pnode)
                return;
-       if (atomic_dec_and_test(&pnode->pnode_count)) {
+       if (atomic_dec_and_test(&pnode->pnode_count))
                __put_pnode(pnode);
-       }
 }
 
 void __init pnode_init(unsigned long );
 struct vfspnode * pnode_alloc(void);
+void pnode_free(struct vfspnode *);
+int pnode_is_busy(struct vfspnode *);
+int pnode_umount_vfs(struct vfspnode *, struct dentry *, struct dentry *, int);
 void pnode_add_slave_mnt(struct vfspnode *, struct vfsmount *);
 void pnode_add_member_mnt(struct vfspnode *, struct vfsmount *);
 void pnode_del_slave_mnt(struct vfsmount *);
@@ -87,4 +89,7 @@ int pnode_prepare_mount(struct vfspnode 
                struct vfsmount *, struct vfsmount *);
 int pnode_commit_mount(struct vfspnode *, int);
 int pnode_abort_mount(struct vfspnode *, struct vfsmount *);
+int pnode_umount(struct vfspnode *, struct dentry *, struct dentry *);
+int pnode_mount_busy(struct vfspnode *, struct dentry *, struct dentry *,
+               struct vfsmount *);
 #endif /* _LINUX_PNODE_H */
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to