commit 982f080c99a4fc3a11a9dc7adf03a895e5dd97a6
Author: Yiannis Pericleous <[EMAIL PROTECTED]>
Date: Sun Feb 25 15:59:06 2007 -0500
inode: removed loops when creating & force remove if it already exists
at branch 0 (and is a whiteout)
diff --git a/fs/unionfs/dirhelper.c b/fs/unionfs/dirhelper.c
index 76df000..4c2b21f 100644
--- a/fs/unionfs/dirhelper.c
+++ b/fs/unionfs/dirhelper.c
@@ -30,11 +30,51 @@ struct unionfs_rdutil_callback {
struct unionfs_dir_state *rdstate;
int mode;
};
+struct unionfs_rmdir_callback {
+ int err;
+ int bindex;
+ int filldir_called;
+ struct dentry *dir;
+ struct vfsmount *mnt;
+};
+static int rmdir_util_callback(void *dirent, const char *name, int namelen,
+ loff_t offset, u64 ino, unsigned int d_type)
+{
+ int err = 0;
+ struct unionfs_rmdir_callback *buf = dirent;
+ struct dentry *dentry;
+
+ buf->filldir_called++;
+
+ if (name[0] == '.' &&
+ (namelen == 1 || (name[1] == '.' && namelen == 2)))
+ goto out;
+ dentry = lookup_one_len(name, buf->dir, namelen);
+ if (IS_ERR(dentry)) {
+ err = PTR_ERR(dentry);
+ goto out;
+ }
+ else if (!dentry->d_inode)
+ BUG_ON(1); /*can this ever happen?*/
+
+ if (d_type == DT_DIR)
+ err = unionfs_force_rmdir(buf->mnt, dentry, buf->bindex);
+ else
+ err = vfs_unlink(buf->dir->d_inode, dentry);
+ dput(dentry);
+out:
+ buf->err = err;
+ return err;
+}
/* This filldir function makes sure only whiteouts exist within a directory. */
static int readdir_util_callback(void *dirent, const char *name, int namelen,
loff_t offset, u64 ino, unsigned int d_type)
{
+ /* FIXME: Fix this so it doesn't store whiteouts and thus is more
+ * efficient
+ */
+
int err = 0;
struct unionfs_rdutil_callback *buf = dirent;
int whiteout = 0;
@@ -327,3 +367,60 @@ out:
return err;
}
+
+/* This function recursively rermoves all the entries of a lower directory
+ * at a specific branch and then the directory itself. It does not
+ * cross branches, and does nothing visible to the union. It should
+ * only be used when both a whiteout and a dir at top branch exists
+ * and we need to create a new dentry
+ */
+int unionfs_force_rmdir(struct vfsmount *mnt, struct dentry *hidden_dentry,
int bindex)
+{
+ int err = 0;
+ struct file *hidden_file;
+ struct unionfs_rmdir_callback *buf = NULL;
+
+ buf = kmalloc(sizeof(struct unionfs_rmdir_callback), GFP_KERNEL);
+ if (!buf) {
+ err = -ENOMEM;
+ goto out;
+ }
+ buf->err = 0;
+ buf->bindex = bindex;
+ buf->dir = hidden_dentry;
+ buf->mnt = mnt;
+
+ if (!hidden_dentry->d_inode)
+ goto out;
+ if (!S_ISDIR(hidden_dentry->d_inode->i_mode))
+ goto out;
+
+ dget(hidden_dentry);
+ mntget(mnt);
+ hidden_file = dentry_open(hidden_dentry, mnt, O_RDONLY);
+ if (IS_ERR(hidden_file)) {
+ err = PTR_ERR(hidden_file);
+ dput(hidden_dentry);
+ goto out;
+ }
+
+ do {
+ buf->filldir_called = 0;
+ err = vfs_readdir(hidden_file, rmdir_util_callback, buf);
+ if (buf->err)
+ err = buf->err;
+ } while ((err >= 0) && buf->filldir_called);
+
+ /* fput calls dput for hidden_dentry */
+ fput(hidden_file);
+
+ if (err < 0)
+ goto out;
+
+ err = vfs_rmdir(hidden_dentry->d_parent->d_inode, hidden_dentry);
+
+out:
+ kfree(buf);
+
+ return err;
+}
diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
index c8da6d1..d47d023 100644
--- a/fs/unionfs/inode.c
+++ b/fs/unionfs/inode.c
@@ -18,15 +18,31 @@
#include "union.h"
+static int do_force_rm(struct dentry *dentry, struct dentry *hidden_dentry,
int bindex)
+{
+ int err;
+
+ /* this should only happen if its a wh */
+ BUG_ON(!UNIONFS_D(dentry)->odf_info->whiteout);
+
+ /* try to remove it! */
+ if (S_ISDIR(hidden_dentry->d_inode->i_mode))
+ err = unionfs_force_rmdir(unionfs_lower_mnt_idx(dentry,
bindex),
+ hidden_dentry, bindex);
+
+ else
+ err = vfs_unlink(hidden_dentry->d_parent->d_inode,
+ hidden_dentry);
+ return err;
+}
+
static int unionfs_create(struct inode *parent, struct dentry *dentry,
int mode, struct nameidata *nd)
{
int err = 0;
struct dentry *hidden_dentry = NULL;
struct dentry *hidden_parent_dentry = NULL;
- int bindex = 0, bstart;
- char *name = NULL;
- int valid = 0;
+ int bstart;
/*
* We have to read-lock the superblock rwsem, and we have to
@@ -56,61 +72,71 @@ static int unionfs_create(struct inode *parent, struct
dentry *dentry,
BUG_ON(!valid && dentry->d_inode);
/* We start out in the leftmost branch. */
- bstart = dbstart(dentry);
- hidden_dentry = unionfs_lower_dentry(dentry);
+ bstart = 0;
- for (bindex = bstart; bindex >= 0; bindex--) {
- hidden_dentry = unionfs_lower_dentry_idx(dentry, bindex);
- if (!hidden_dentry) {
- /* if hidden_dentry is NULL, create the entire
- * dentry directory structure in branch 'bindex'.
- * hidden_dentry will NOT be null when bindex == bstart
- * because lookup passed as a negative unionfs dentry
- * pointing to a lone negative underlying dentry */
- hidden_dentry = create_parents(parent, dentry, bindex);
- if (!hidden_dentry || IS_ERR(hidden_dentry)) {
- if (IS_ERR(hidden_dentry))
- err = PTR_ERR(hidden_dentry);
- continue;
- }
+ hidden_dentry = unionfs_lower_dentry_idx(dentry, bstart);
+ if (!hidden_dentry) {
+ /* if hidden_dentry is NULL, create the entire
+ * dentry directory structure in branch 'bindex'.
+ * hidden_dentry will NOT be null when bindex == bstart
+ * because lookup passed as a negative unionfs dentry
+ * pointing to a lone negative underlying dentry */
+ hidden_dentry = create_parents(parent, dentry, bstart);
+ if (!hidden_dentry || IS_ERR(hidden_dentry)) {
+ if (IS_ERR(hidden_dentry))
+ err = PTR_ERR(hidden_dentry);
+ goto out;
}
+ }
+
+ if (hidden_dentry->d_inode)
+ do_force_rm(dentry, hidden_dentry, bstart);
+ /* FIXME: Now this case should never happen, but for some
+ * reason rmdir above does not give a negative dentry
+ */
- hidden_parent_dentry = lock_parent(hidden_dentry);
- if (IS_ERR(hidden_parent_dentry)) {
- err = PTR_ERR(hidden_parent_dentry);
+ if (hidden_dentry->d_inode) {
+ hidden_dentry = lookup_one_len(dentry->d_name.name,
+ hidden_dentry->d_parent, dentry->d_name.len);
+ if (!hidden_dentry || IS_ERR(hidden_dentry)) {
+ if (IS_ERR(hidden_dentry))
+ err = PTR_ERR(hidden_dentry);
goto out;
}
- /* We shouldn't create things in a read-only branch. */
- if (!(err = is_robranch_super(dentry->d_sb, bindex)))
- err = vfs_create(hidden_parent_dentry->d_inode,
- hidden_dentry, mode, nd);
-
- if (err || !hidden_dentry->d_inode) {
- unlock_dir(hidden_parent_dentry);
-
- /* break out of for loop if the error wasn't -EROFS */
- if (!IS_COPYUP_ERR(err))
- break;
- } else {
- err = odf_lookup(dentry->d_parent, dentry,
- ODF_LOOKUP_FILE|ODF_LOOKUP_RMV_WH);
- if (!err)
- err = odf_purge_dir_cache(dentry->d_parent);
- if (!err)
- err = unionfs_interpose(dentry, parent->i_sb,
0);
- if (!err) {
- fsstack_copy_attr_times(parent,
- hidden_parent_dentry->d_inode);
- fsstack_copy_inode_size(parent,
- hidden_parent_dentry->d_inode);
- /* update number of links on parent directory */
- parent->i_nlink = unionfs_get_nlinks(parent);
- }
- unlock_dir(hidden_parent_dentry);
- break;
+ }
+
+ hidden_parent_dentry = lock_parent(hidden_dentry);
+ if (IS_ERR(hidden_parent_dentry)) {
+ err = PTR_ERR(hidden_parent_dentry);
+ goto out;
+ }
+ /* We shouldn't create things in a read-only branch. */
+ if (!(err = is_robranch_super(dentry->d_sb, bstart)))
+ err = vfs_create(hidden_parent_dentry->d_inode,
+ hidden_dentry, mode, nd);
+
+ if (err || !hidden_dentry->d_inode)
+ unlock_dir(hidden_parent_dentry);
+
+ else {
+ err = odf_lookup(dentry->d_parent, dentry,
+ ODF_LOOKUP_FILE|ODF_LOOKUP_RMV_WH);
+ if (!err)
+ err = odf_purge_dir_cache(dentry->d_parent);
+ if (!err)
+ err = unionfs_interpose(dentry, parent->i_sb, 0);
+ if (!err) {
+ fsstack_copy_attr_times(parent,
+ hidden_parent_dentry->d_inode);
+ fsstack_copy_inode_size(parent,
+ hidden_parent_dentry->d_inode);
+ /* update number of links on parent directory */
+ parent->i_nlink = unionfs_get_nlinks(parent);
}
+ unlock_dir(hidden_parent_dentry);
}
+
out:
unionfs_unlock_dentry(dentry);
unionfs_read_unlock(dentry->d_sb);
@@ -235,78 +261,82 @@ static int unionfs_symlink(struct inode *dir, struct
dentry *dentry,
struct dentry *hidden_dentry = NULL;
struct dentry *hidden_dir_dentry = NULL;
umode_t mode;
- int bindex = 0, bstart;
+ int bstart;
BUG_ON(!is_valid_dentry(dentry));
unionfs_lock_dentry(dentry);
- /* We start out in the leftmost branch. */
- bstart = dbstart(dentry);
-
- hidden_dentry = unionfs_lower_dentry(dentry);
+ /* We create in the leftmost branch. */
+ bstart = 0;
- /* do a normal vfs_symlink()
- * with possible recursive directory creation
- */
- for (bindex = bstart; bindex >= 0; bindex--) {
- hidden_dentry = unionfs_lower_dentry_idx(dentry, bindex);
- if (!hidden_dentry) {
- /* if hidden_dentry is NULL, create the entire
- * dentry directory structure in branch 'bindex'.
- * hidden_dentry will NOT be null when bindex ==
- * bstart because lookup passed as a negative
- * unionfs dentry pointing to a lone negative
- * underlying dentry
- */
- hidden_dentry = create_parents(dir, dentry, bindex);
- if (!hidden_dentry || IS_ERR(hidden_dentry)) {
- if (IS_ERR(hidden_dentry))
- err = PTR_ERR(hidden_dentry);
+ hidden_dentry = unionfs_lower_dentry_idx(dentry, bstart);
+ if (!hidden_dentry) {
+ /* if hidden_dentry is NULL, create the entire
+ * dentry directory structure in branch 'bindex'.
+ * hidden_dentry will NOT be null when bindex ==
+ * bstart because lookup passed as a negative
+ * unionfs dentry pointing to a lone negative
+ * underlying dentry
+ */
+ hidden_dentry = create_parents(dir, dentry, bstart);
+ if (!hidden_dentry || IS_ERR(hidden_dentry)) {
+ if (IS_ERR(hidden_dentry))
+ err = PTR_ERR(hidden_dentry);
printk(KERN_DEBUG "hidden dentry NULL (or
error)"
- "for bindex = %d\n", bindex);
- continue;
- }
+ "for bindex = %d\n", bstart);
+ goto out;
}
+ }
- hidden_dir_dentry = lock_parent(hidden_dentry);
-
- if (!(err = is_robranch_super(dentry->d_sb, bindex))) {
- mode = S_IALLUGO;
- err =
- vfs_symlink(hidden_dir_dentry->d_inode,
- hidden_dentry, symname, mode);
+ if (hidden_dentry->d_inode)
+ do_force_rm(dentry, hidden_dentry, bstart);
+ /* FIXME: Now this case should never happen, but for some
+ * reason rmdir above does not give a negative dentry
+ */
+ if (hidden_dentry->d_inode) {
+ hidden_dentry = lookup_one_len(dentry->d_name.name,
+ hidden_dentry->d_parent, dentry->d_name.len);
+ if (!hidden_dentry || IS_ERR(hidden_dentry)) {
+ if (IS_ERR(hidden_dentry))
+ err = PTR_ERR(hidden_dentry);
+ goto out;
}
- unlock_dir(hidden_dir_dentry);
-
- if (err || !hidden_dentry->d_inode) {
- /* break out of for loop if error returned was NOT
-EROFS */
- if (!IS_COPYUP_ERR(err))
- break;
- } else {
- /* update odf and remove any wh before interpose*/
- err = odf_lookup(dentry->d_parent, dentry,
- ODF_LOOKUP_FILE|ODF_LOOKUP_RMV_WH);
- if (!err)
- err = unionfs_interpose(dentry, dir->i_sb, 0);
- if (!err)
- err = odf_purge_dir_cache(dentry->d_parent);
- if (!err) {
- fsstack_copy_attr_times(dir,
- hidden_dir_dentry->d_inode);
- fsstack_copy_inode_size(dir,
- hidden_dir_dentry->d_inode);
- /* update number of links on parent directory */
- dir->i_nlink = unionfs_get_nlinks(dir);
- }
- break;
+ }
+
+ hidden_dir_dentry = lock_parent(hidden_dentry);
+
+ if (!(err = is_robranch_super(dentry->d_sb, bstart))) {
+ mode = S_IALLUGO;
+ err =
+ vfs_symlink(hidden_dir_dentry->d_inode,
+ hidden_dentry, symname, mode);
+ }
+ unlock_dir(hidden_dir_dentry);
+
+ if (!(err || !hidden_dentry->d_inode)) {
+ /* update odf and remove any wh before interpose*/
+ err = odf_lookup(dentry->d_parent, dentry,
+ ODF_LOOKUP_FILE|ODF_LOOKUP_RMV_WH);
+ if (!err)
+ err = unionfs_interpose(dentry, dir->i_sb, 0);
+ if (!err)
+ err = odf_purge_dir_cache(dentry->d_parent);
+ if (!err) {
+ fsstack_copy_attr_times(dir,
+ hidden_dir_dentry->d_inode);
+ fsstack_copy_inode_size(dir,
+ hidden_dir_dentry->d_inode);
+ /* update number of links on parent directory */
+ dir->i_nlink = unionfs_get_nlinks(dir);
}
}
if (!dentry->d_inode)
d_drop(dentry);
+out:
unionfs_unlock_dentry(dentry);
return err;
}
@@ -336,10 +366,25 @@ static int unionfs_mkdir(struct inode *parent, struct
dentry *dentry, int mode)
printk(KERN_DEBUG "hidden dentry NULL for "
"bindex = %d\n", bindex);
err = PTR_ERR(hidden_dentry);
- goto out;;
+ goto out;
}
}
+ if (hidden_dentry->d_inode)
+ do_force_rm(dentry, hidden_dentry, bindex);
+ /* FIXME: Now this case should never happen, but for some
+ * reason rmdir above does not give a negative dentry
+ */
+ if (hidden_dentry->d_inode) {
+ hidden_dentry = lookup_one_len(dentry->d_name.name,
+ hidden_dentry->d_parent, dentry->d_name.len);
+ if (!hidden_dentry || IS_ERR(hidden_dentry)) {
+ if (IS_ERR(hidden_dentry))
+ err = PTR_ERR(hidden_dentry);
+ goto out;
+ }
+ }
+
hidden_parent_dentry = lock_parent(hidden_dentry);
if (IS_ERR(hidden_parent_dentry)) {
@@ -402,62 +447,72 @@ static int unionfs_mknod(struct inode *dir, struct dentry
*dentry, int mode,
int err = 0;
struct dentry *hidden_dentry = NULL;
struct dentry *hidden_parent_dentry = NULL;
- int bindex = 0, bstart;
+ int bstart;
BUG_ON(!is_valid_dentry(dentry));
unionfs_lock_dentry(dentry);
- bstart = dbstart(dentry);
+ bstart = 0;
- hidden_dentry = unionfs_lower_dentry(dentry);
-
- for (bindex = bstart; bindex >= 0; bindex--) {
- if (is_robranch_super(dentry->d_sb, bindex))
- continue;
+ if (is_robranch_super(dentry->d_sb, bstart))
+ goto out;
- hidden_dentry = unionfs_lower_dentry_idx(dentry, bindex);
- if (!hidden_dentry) {
- hidden_dentry = create_parents(dir, dentry, bindex);
- if (IS_ERR(hidden_dentry)) {
- printk(KERN_DEBUG
- "failed to create parents on %d, err =
%ld\n",
- bindex, PTR_ERR(hidden_dentry));
- continue;
- }
+ hidden_dentry = unionfs_lower_dentry_idx(dentry, bstart);
+ if (!hidden_dentry) {
+ hidden_dentry = create_parents(dir, dentry, bstart);
+ if (IS_ERR(hidden_dentry)) {
+ printk(KERN_DEBUG
+ "failed to create parents on %d, err = %ld\n",
+ bstart, PTR_ERR(hidden_dentry));
+ goto out;
}
-
- hidden_parent_dentry = lock_parent(hidden_dentry);
- if (IS_ERR(hidden_parent_dentry)) {
- err = PTR_ERR(hidden_parent_dentry);
+ }
+
+ if (hidden_dentry->d_inode)
+ do_force_rm(dentry, hidden_dentry, bstart);
+ /* FIXME: Now this case should never happen, but for some
+ * reason rmdir above does not give a negative dentry
+ */
+ if (hidden_dentry->d_inode) {
+ hidden_dentry = lookup_one_len(dentry->d_name.name,
+ hidden_dentry->d_parent, dentry->d_name.len);
+ if (!hidden_dentry || IS_ERR(hidden_dentry)) {
+ if (IS_ERR(hidden_dentry))
+ err = PTR_ERR(hidden_dentry);
goto out;
}
+ }
- err = vfs_mknod(hidden_parent_dentry->d_inode,
- hidden_dentry, mode, dev);
+ hidden_parent_dentry = lock_parent(hidden_dentry);
+ if (IS_ERR(hidden_parent_dentry)) {
+ err = PTR_ERR(hidden_parent_dentry);
+ goto out;
+ }
- if (err) {
- unlock_dir(hidden_parent_dentry);
- break;
- }
- /* update odf and remove any wh before interpose*/
- err = odf_lookup(dentry->d_parent, dentry,
- ODF_LOOKUP_FILE|ODF_LOOKUP_RMV_WH);
- if (!err)
- err = odf_purge_dir_cache(dentry->d_parent);
- if (!err)
- err = unionfs_interpose(dentry, dir->i_sb, 0);
- if (!err) {
- fsstack_copy_attr_times(dir,
- hidden_parent_dentry->d_inode);
- fsstack_copy_inode_size(dir,
- hidden_parent_dentry->d_inode);
- /* update number of links on parent directory */
- dir->i_nlink = unionfs_get_nlinks(dir);
- }
+ err = vfs_mknod(hidden_parent_dentry->d_inode,
+ hidden_dentry, mode, dev);
+
+ if (err) {
unlock_dir(hidden_parent_dentry);
+ goto out;
+ }
- break;
+ /* update odf and remove any wh before interpose*/
+ err = odf_lookup(dentry->d_parent, dentry,
+ ODF_LOOKUP_FILE|ODF_LOOKUP_RMV_WH);
+ if (!err)
+ err = odf_purge_dir_cache(dentry->d_parent);
+ if (!err)
+ err = unionfs_interpose(dentry, dir->i_sb, 0);
+ if (!err) {
+ fsstack_copy_attr_times(dir,
+ hidden_parent_dentry->d_inode);
+ fsstack_copy_inode_size(dir,
+ hidden_parent_dentry->d_inode);
+ /* update number of links on parent directory */
+ dir->i_nlink = unionfs_get_nlinks(dir);
}
+ unlock_dir(hidden_parent_dentry);
out:
if (!dentry->d_inode)
diff --git a/fs/unionfs/odf.c b/fs/unionfs/odf.c
index 5442c78..cad8d86 100644
--- a/fs/unionfs/odf.c
+++ b/fs/unionfs/odf.c
@@ -589,7 +589,7 @@ out:
int odf_purge_dir_cache(struct dentry *dentry)
{
int err = 0;
- struct iattr attr;
+ //struct iattr attr;
struct odf_dentry_info *odi = NULL;
odi = odf_ic_dir(dentry);
@@ -809,13 +809,6 @@ int __odf_set_opaque(struct inode *i, int branch)
return err;
}
-void print_uuid(unsigned char *uuid)
-{
- int i;
- for (i = 0; i < 4; i++){
- printk("%x-", *((unsigned int *) ((uuid+i*4))));
}
- printk("\n");
-}
/*
* Requires an odf_sb_info, returns the dirs= part of the mount options
*/
@@ -887,7 +880,6 @@ char *odf_get_options(struct odf_sb_info *odf_sb)
file->f_op->read(file, (char*)&le32, sizeof(__le32),
&file->f_pos);
perms = le32_to_cpu(le32);
file->f_op->read(file, (char*)uuid, UUID_LEN, &file->f_pos);
- print_uuid(uuid);
ptr+=len;
if (perms == MAY_READ)
sprintf(ptr,"=ro:");
@@ -1025,7 +1017,6 @@ int odf_put_options(struct super_block* sb_union, struct
unionfs_dentry_info *hi
generate_random_uuid(uuid + count * UUID_LEN);
else
memcpy(uuid + count * UUID_LEN, uuid + i * UUID_LEN,
UUID_LEN);
- print_uuid(uuid + count * UUID_LEN);
bid[count] = (u32)m;
/* write */
diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
index 20318fa..31e3ca2 100644
--- a/fs/unionfs/union.h
+++ b/fs/unionfs/union.h
@@ -311,6 +311,7 @@ int unionfs_unlink(struct inode *dir, struct dentry
*dentry);
int unionfs_rmdir(struct inode *dir, struct dentry *dentry);
int __unionfs_d_revalidate_chain(struct dentry *dentry, struct nameidata *nd);
+int unionfs_force_rmdir(struct vfsmount *mnt, struct dentry *hidden_dentry,
int bindex);
/* The values for unionfs_interpose's flag. */
#define INTERPOSE_DEFAULT 0
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs