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