From: Erez Zadok <[EMAIL PROTECTED]>

Properly increase/release lower vfsmounts.
Validate proper use of unionfs mntget/put.

Signed-off-by: Erez Zadok <[EMAIL PROTECTED]>
Signed-off-by: Josef 'Jeff' Sipek <[EMAIL PROTECTED]>
---
 fs/unionfs/dentry.c |    6 ++++--
 fs/unionfs/inode.c  |   11 +++++++++++
 fs/unionfs/lookup.c |   11 ++++++-----
 fs/unionfs/union.h  |   47 +++++++++++++++++++++++++++++++++++++++--------
 4 files changed, 60 insertions(+), 15 deletions(-)

diff --git a/fs/unionfs/dentry.c b/fs/unionfs/dentry.c
index c7bbeca..0be958f 100644
--- a/fs/unionfs/dentry.c
+++ b/fs/unionfs/dentry.c
@@ -450,9 +450,11 @@ static void unionfs_d_release(struct dentry *dentry)
        bend = dbend(dentry);
        for (bindex = bstart; bindex <= bend; bindex++) {
                dput(unionfs_lower_dentry_idx(dentry, bindex));
-               unionfs_mntput(dentry, bindex);
-
                unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
+               /* NULL lower mnt is ok if this is a negative dentry */
+               if (!dentry->d_inode && !unionfs_lower_mnt_idx(dentry,bindex))
+                       continue;
+               unionfs_mntput(dentry, bindex);
                unionfs_set_lower_mnt_idx(dentry, bindex, NULL);
        }
        /* free private data (unionfs_dentry_info) here */
diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
index a219a40..d6a79d5 100644
--- a/fs/unionfs/inode.c
+++ b/fs/unionfs/inode.c
@@ -222,8 +222,11 @@ out:
        dput(wh_dentry);
        kfree(name);
 
+       if (!err)
+               unionfs_postcopyup_setmnt(dentry);
        unionfs_unlock_dentry(dentry);
        unionfs_read_unlock(dentry->d_sb);
+
        return err;
 }
 
@@ -563,8 +566,12 @@ out:
                d_drop(dentry);
 
        kfree(name);
+       if (!err)
+               unionfs_postcopyup_setmnt(dentry);
        unionfs_unlock_dentry(dentry);
+
        unionfs_read_unlock(dentry->d_sb);
+
        return err;
 }
 
@@ -835,8 +842,12 @@ out:
 
        kfree(name);
 
+       if (!err)
+               unionfs_postcopyup_setmnt(dentry);
        unionfs_unlock_dentry(dentry);
+
        unionfs_read_unlock(dentry->d_sb);
+
        return err;
 }
 
diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
index 152d421..38ee21f 100644
--- a/fs/unionfs/lookup.c
+++ b/fs/unionfs/lookup.c
@@ -314,24 +314,25 @@ out_negative:
        if (lookupmode == INTERPOSE_REVAL) {
                if (dentry->d_inode)
                        UNIONFS_I(dentry->d_inode)->stale = 1;
-
                goto out;
        }
        /* This should only happen if we found a whiteout. */
        if (first_dentry_offset == -1) {
                first_lower_dentry = lookup_one_len(name, lower_dir_dentry,
-                                                    namelen);
+                                                   namelen);
                first_dentry_offset = bindex;
                if (IS_ERR(first_lower_dentry)) {
                        err = PTR_ERR(first_lower_dentry);
                        goto out;
                }
-               
-               /* FIXME: the following line needs to be changed to allow
+
+               /*
+                * FIXME: the following line needs to be changed to allow
                 * mount-point crossing
                 */
                first_dentry = dentry;
-               first_lower_mnt = unionfs_mntget(dentry, bindex);
+               first_lower_mnt = unionfs_mntget(dentry->d_sb->s_root,
+                                                bindex);
        }
        unionfs_set_lower_dentry_idx(dentry, first_dentry_offset,
                                     first_lower_dentry);
diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
index 9f3e68a..33c2137 100644
--- a/fs/unionfs/union.h
+++ b/fs/unionfs/union.h
@@ -459,18 +459,49 @@ static inline void unlock_dir(struct dentry *dir)
 static inline struct vfsmount *unionfs_mntget(struct dentry *dentry,
                                              int bindex)
 {
-       BUG_ON(!dentry || bindex < 0);
-
-       return mntget(unionfs_lower_mnt_idx(dentry, bindex));
+       struct vfsmount *mnt;
+
+       if (!dentry) {
+               if (bindex < 0)
+                       return NULL;
+               if (!dentry && bindex >= 0) {
+                       return NULL;
+               }
+       }
+       mnt = unionfs_lower_mnt_idx(dentry, bindex);
+       if (!mnt) {
+               if (bindex < 0)
+                       return NULL;
+               if (!mnt && bindex >= 0) {
+                       return NULL;
+               }
+       }
+       mnt = mntget(mnt);
+       return mnt;
 }
 
 static inline void unionfs_mntput(struct dentry *dentry, int bindex)
 {
-       if (!dentry)
-               return;
+       struct vfsmount *mnt;
+
+       if (!dentry) {
+               if (bindex < 0)
+                       return;
+               if (!dentry && bindex >= 0) {
+                       return;
+               }
+       }
+       mnt = unionfs_lower_mnt_idx(dentry, bindex);
+       if (!mnt) {
+               if (bindex < 0)
+                       return;
+               if (!mnt && bindex >= 0) {
+                       return;
+               }
+       }
+       mntput(mnt);
+}
+
 
-       BUG_ON(bindex < 0);
 
-       mntput(unionfs_lower_mnt_idx(dentry, bindex));
-}
 #endif /* not _UNION_H_ */
-- 
1.5.2.2.238.g7cbf2f2

-
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