Bernhard, I've been testing several patches to deal with open/unlinked files
and truncated files. This patch below seems to fix everything I've seen so far
(it's actually a merge of several smaller patches, but I'm sending it as one
larger one for convenience). Apply this on top of 2.6.37.y, with unionfs 2.5.8.
Cheers,
Erez.
diff --git a/fs/unionfs/commonfops.c b/fs/unionfs/commonfops.c
index 51ea65e..0f6cba3 100644
--- a/fs/unionfs/commonfops.c
+++ b/fs/unionfs/commonfops.c
@@ -312,7 +312,7 @@ static int __unionfs_file_revalidate(struct file *file,
struct dentry *dentry,
* someone has copied up this file from underneath us, we also need
* to refresh things.
*/
- if (d_deleted(dentry) ||
+ if ((d_deleted(dentry) && dbstart(dentry) >= fbstart(file)) ||
(sbgen <= fgen &&
dbstart(dentry) == fbstart(file) &&
unionfs_lower_file(file)))
@@ -506,8 +506,11 @@ static int __open_file(struct inode *inode, struct file
*file,
for (bindex = bstart - 1; bindex >= 0; bindex--) {
err = copyup_file(parent->d_inode, file,
bstart, bindex, size);
- if (!err)
+ if (!err) {
+ /* only one regular file open */
+ fbend(file) = fbstart(file);
break;
+ }
}
return err;
} else {
diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
index cc994bd..1905a32 100644
--- a/fs/unionfs/inode.c
+++ b/fs/unionfs/inode.c
@@ -933,7 +933,12 @@ static int unionfs_setattr(struct dentry *dentry, struct
iattr *ia)
err = -EINVAL;
goto out;
}
- lower_inode = unionfs_lower_inode(inode);
+
+ /*
+ * Get the lower inode directly from lower dentry, in case ibstart
+ * is -1 (which happens when the file is open but unlinked.
+ */
+ lower_inode = lower_dentry->d_inode;
/* check if user has permission to change lower inode */
err = inode_change_ok(lower_inode, ia);
@@ -968,6 +973,16 @@ static int unionfs_setattr(struct dentry *dentry, struct
iattr *ia)
/* get updated lower_dentry/inode after copyup */
lower_dentry = unionfs_lower_dentry(dentry);
lower_inode = unionfs_lower_inode(inode);
+ /*
+ * check for whiteouts in writeable branch, and remove them
+ * if necessary.
+ */
+ if (lower_dentry) {
+ err = check_unlink_whiteout(dentry, lower_dentry,
+ bindex);
+ if (err > 0) /* ignore if whiteout found and removed */
+ err = 0;
+ }
}
/*
diff --git a/fs/unionfs/whiteout.c b/fs/unionfs/whiteout.c
index 405073a..9abe566 100644
--- a/fs/unionfs/whiteout.c
+++ b/fs/unionfs/whiteout.c
@@ -203,8 +203,8 @@ int unlink_whiteout(struct dentry *wh_dentry)
* Checks to see if there's a whiteout in @lower_dentry's parent directory,
* whose name is taken from @dentry. Then tries to remove that whiteout, if
* found. If <dentry,bindex> is a branch marked readonly, return -EROFS.
- * If it finds both a regular file and a whiteout, return -EIO (this should
- * never happen).
+ * If it finds both a regular file and a whiteout, delete whiteout (this
+ * should never happen).
*
* Return 0 if no whiteout was found. Return 1 if one was found and
* successfully removed. Therefore a value >= 0 tells the caller that
@@ -234,13 +234,10 @@ int check_unlink_whiteout(struct dentry *dentry, struct
dentry *lower_dentry,
}
/* check if regular file and whiteout were both found */
- if (unlikely(lower_dentry->d_inode)) {
- err = -EIO;
- printk(KERN_ERR "unionfs: found both whiteout and regular "
- "file in directory %s (branch %d)\n",
+ if (unlikely(lower_dentry->d_inode))
+ printk(KERN_WARNING "unionfs: removing whiteout; regular "
+ "file exists in directory %s (branch %d)\n",
lower_dir_dentry->d_name.name, bindex);
- goto out_dput;
- }
/* check if branch is writeable */
err = is_robranch_super(dentry->d_sb, bindex);
_______________________________________________
unionfs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs