commit 049aff0db605f927bfb536ae20b00a2581816d90
Author: Yiannis Pericleous <[EMAIL PROTECTED]>
Date:   Mon May 14 19:22:46 2007 -0400

    bugfix: fixed interpose to check if d_splice_alias returns a dentry
    
    and make sure this new dentry's pd is  corrent.
    unionfs_interpose now returns a dentry if d_splice_alias has returned
    a dentry

diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
index 63b8a4a..50cfc93 100644
--- a/fs/unionfs/inode.c
+++ b/fs/unionfs/inode.c
@@ -96,7 +96,8 @@ static int unionfs_create(struct inode *parent, struct dentry 
*dentry,
                if (!err)
                        err = odf_purge_dir_cache(dentry->d_parent);
                if (!err)
-                       err = unionfs_interpose(dentry, parent->i_sb, 0);
+                       /* only INTERPOSE_LOOKUP can return a value other than 
0 or err */
+                       err = PTR_ERR(unionfs_interpose(dentry, parent->i_sb, 
0));
                if (!err) {
                        fsstack_copy_attr_times(parent,
                                        hidden_parent_dentry->d_inode);
@@ -315,7 +316,8 @@ static int unionfs_symlink(struct inode *dir, struct dentry 
*dentry,
                err = odf_lookup(dentry->d_parent, dentry,
                        ODF_LOOKUP_FILE|ODF_LOOKUP_RMV_WH);
                if (!err)
-                       err = unionfs_interpose(dentry, dir->i_sb, 0);
+                       /* only INTERPOSE_LOOKUP can return a value other than 
0 or err */
+                       err = PTR_ERR(unionfs_interpose(dentry, dir->i_sb, 0));
                if (!err)
                        err = odf_purge_dir_cache(dentry->d_parent);
                if (!err) {
@@ -406,7 +408,9 @@ static int unionfs_mkdir(struct inode *parent, struct 
dentry *dentry, int mode)
        err = odf_purge_dir_cache(dentry->d_parent);
        if (err)
                goto out;
-       err = unionfs_interpose(dentry, parent->i_sb, bindex);
+       
+       /* only INTERPOSE_LOOKUP can return a value other than 0 or err */
+       err = PTR_ERR(unionfs_interpose(dentry, parent->i_sb, 0));
        if (!err) {
                fsstack_copy_attr_times(parent,
                                hidden_parent_dentry->d_inode);
@@ -480,7 +484,8 @@ static int unionfs_mknod(struct inode *dir, struct dentry 
*dentry, int mode,
        if (!err)
                err = odf_purge_dir_cache(dentry->d_parent);
        if (!err)
-               err = unionfs_interpose(dentry, dir->i_sb, 0);
+               /* only INTERPOSE_LOOKUP can return a value other than 0 or err 
*/
+               err = PTR_ERR(unionfs_interpose(dentry, dir->i_sb, 0));
        if (!err) {
                fsstack_copy_attr_times(dir,
                                hidden_parent_dentry->d_inode);
diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
index f8adf89..c7bcac1 100644
--- a/fs/unionfs/lookup.c
+++ b/fs/unionfs/lookup.c
@@ -26,6 +26,7 @@ struct dentry *unionfs_lookup_backend(struct dentry *dentry, 
struct nameidata *n
        struct dentry *hidden_dentry = NULL;
        struct dentry *hidden_dir_dentry = NULL;
        struct dentry *parent_dentry = NULL;
+       struct dentry *d_interposed = NULL;
        int bindex, bstart, bend, bopaque;
        int dentry_count = 0;   /* Number of positive dentries. */
        int first_dentry_offset = -1; /* -1 is uninitialized */
@@ -279,7 +280,13 @@ out_positive:
                bend = dbend(dentry);
        }
 
-       err = unionfs_interpose(dentry, dentry->d_sb, lookupmode);
+       /* interpose can return a dentry if d_splice returned a different 
dentry */
+       d_interposed = unionfs_interpose(dentry, dentry->d_sb, lookupmode);
+       if (IS_ERR(d_interposed))
+               err = PTR_ERR(d_interposed);
+       else if(d_interposed)
+               dentry = d_interposed;
+
        if (err)
                goto out_drop;
 
@@ -322,6 +329,8 @@ out:
        dput(parent_dentry);
        if (locked_child || (err && allocated_new_info))
                unionfs_unlock_dentry(dentry);
+       if (!err && d_interposed)
+               return d_interposed;
        return ERR_PTR(err);
 }
 
diff --git a/fs/unionfs/main.c b/fs/unionfs/main.c
index ac08397..72e62fc 100644
--- a/fs/unionfs/main.c
+++ b/fs/unionfs/main.c
@@ -26,7 +26,7 @@
  *
  * @sb: unionfs's super_block
  */
-int unionfs_interpose(struct dentry *dentry, struct super_block *sb, int flag)
+struct dentry *unionfs_interpose(struct dentry *dentry, struct super_block 
*sb, int flag)
 {
        struct inode *hidden_inode;
        struct dentry *hidden_dentry;
@@ -34,7 +34,8 @@ int unionfs_interpose(struct dentry *dentry, struct 
super_block *sb, int flag)
        struct inode *inode;
        int is_negative_dentry = 1, odf_flag = ODF_LOOKUP_FILE;
        int bindex, bstart, bend;
-       int opaque;
+       int opaque, skipped = 1;
+       struct dentry *spliced = NULL;
 
        verify_locked(dentry);
 
@@ -102,11 +103,12 @@ int unionfs_interpose(struct dentry *dentry, struct 
super_block *sb, int flag)
                        err = -EACCES;
                        goto out;
                }
-
                if (atomic_read(&inode->i_count) > 1)
                        goto skip;
        }
 
+fill_i_info:
+       skipped = 0;
        for (bindex = bstart; bindex <= bend; bindex++) {
                hidden_dentry = unionfs_lower_dentry_idx(dentry, bindex);
                if (!hidden_dentry) {
@@ -147,7 +149,9 @@ int unionfs_interpose(struct dentry *dentry, struct 
super_block *sb, int flag)
        /* all well, copy inode attributes */
        fsstack_copy_attr_all(inode, hidden_inode, unionfs_get_nlinks);
        fsstack_copy_inode_size(inode, hidden_inode);
-
+       
+       if(spliced) 
+               goto out_spliced;
 skip:
        /* only (our) lookup wants to do a d_add */
        switch (flag) {
@@ -156,7 +160,25 @@ skip:
                d_instantiate(dentry, inode);
                break;
        case INTERPOSE_LOOKUP:
-               err = PTR_ERR(d_splice_alias(inode, dentry));
+               spliced = d_splice_alias(inode, dentry);
+               if (IS_ERR(spliced))
+                       err = PTR_ERR(spliced);
+
+               /* d_splice can return a dentry if it was disconnected
+                * and had to be moved. We must make sure that the pd
+                * of the new dentry is correct and that the inode info
+                * was filled properly. Finally we must return this new 
+                * dentry
+                */
+               else if (spliced && spliced != dentry) {
+                       spliced->d_op = &unionfs_dops;
+                       spliced->d_fsdata = dentry->d_fsdata;
+                       dentry->d_fsdata = NULL;
+                       dentry = spliced;
+                       if (skipped)
+                               goto fill_i_info;
+                       goto out_spliced;
+               }
                break;
        case INTERPOSE_REVAL:
                /* Do nothing. */
@@ -165,9 +187,13 @@ skip:
                printk(KERN_ERR "unionfs: invalid interpose flag passed!");
                BUG();
        }
+       goto out;
 
+out_spliced:
+       if (!err)
+               return spliced;
 out:
-       return err;
+       return ERR_PTR(err);
 }
 
 /* like interpose above, but for an already existing dentry */
@@ -719,7 +745,8 @@ static int unionfs_read_super(struct super_block *sb, void 
*raw_data,
        atomic_set(&UNIONFS_D(sb->s_root)->generation, 1);
 
        /* call interpose to create the upper level inode */
-       err = unionfs_interpose(sb->s_root, sb, 0);
+       /* only INTERPOSE_LOOKUP can return a value other than 0 or err */
+       err = PTR_ERR(unionfs_interpose(sb->s_root, sb, 0));
        unionfs_unlock_dentry(sb->s_root);
        if (!err) {
                /* its now ok to start the cleanup thread */
diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
index b6c98da..7f0827f 100644
--- a/fs/unionfs/union.h
+++ b/fs/unionfs/union.h
@@ -323,7 +323,7 @@ int unionfs_silly_rename(struct dentry *dentry, struct 
dentry *hidden_dentry);
 #define INTERPOSE_REVAL_NEG    3
 #define INTERPOSE_PARTIAL      4
 
-extern int unionfs_interpose(struct dentry *this_dentry,
+extern struct dentry *unionfs_interpose(struct dentry *this_dentry,
                             struct super_block *sb, int flag);
 
 #ifdef CONFIG_UNION_FS_XATTR
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs

Reply via email to