commit 39ad12d94c0c04d4625e4b2a524ec96bf8c0fee9
Author: Yiannis Pericleous <[EMAIL PROTECTED]>
Date:   Fri Feb 9 14:33:27 2007 -0500

    Rename.

diff --git a/fs/unionfs/odf.c b/fs/unionfs/odf.c
index 546cfea..9d5d11d 100644
--- a/fs/unionfs/odf.c
+++ b/fs/unionfs/odf.c
@@ -127,7 +127,9 @@ int odf_reclaim(struct dentry *dentry)
        /* this should never happen */
        BUG_ON(new_dentry->d_inode);
        
+       lock_rename(old_dentry->d_parent, new_dentry->d_parent);
        err = vfs_rename(old_dir, old_dentry, new_dir, new_dentry);
+       unlock_rename(old_dentry->d_parent, new_dentry->d_parent);      
        dput(new_dentry);
 
 out_unlock:
@@ -140,6 +142,55 @@ out:
 }
 
 /*
+ * Rename in odf, expects UnionFS dentries.
+ * If the new_dentry exists (either as a file or wh)
+ * it is removed using odf_remove (ie dirs are reclaimed)
+ */
+int odf_rename(struct dentry *old_dentry, struct dentry *new_dentry)
+{
+       struct dentry *old_dir, *new_dir;
+       struct dentry *old_odfdentry, *new_odfdentry;
+       int err = 0;
+
+       UNIONFS_D(old_dentry)->odf_info = odf_lookup(
+                               old_dentry->d_parent,
+                               old_dentry,
+                               0);
+       UNIONFS_D(new_dentry)->odf_info = odf_lookup(
+                               new_dentry->d_parent,
+                               new_dentry,
+                               0);
+
+       /* if new exists, remove it */
+       if (UNIONFS_D(new_dentry)->odf_info)
+               err = odf_remove(new_dentry, ODF_RMV_ANY);
+               
+       old_odfdentry = UNIONFS_D(old_dentry)->odf_info->dentry;
+       old_dir = old_odfdentry->d_parent;
+       new_dir = (UNIONFS_D(new_dentry->d_parent))->odf_info->dentry;
+       new_odfdentry = lookup_one_len(
+                               new_dentry->d_name.name,
+                               new_dir,
+                               new_dentry->d_name.len);
+       if (IS_ERR(new_odfdentry)) { 
+               err = PTR_ERR(new_odfdentry);
+               goto out;
+       }
+       
+       /* this should never happen */
+       BUG_ON(new_odfdentry->d_inode);
+       
+       lock_rename(old_dir, new_dir);
+       err = vfs_rename(old_dir->d_inode, 
+                       old_odfdentry, new_dir->d_inode, 
+                       new_odfdentry);
+       unlock_rename(old_dir, new_dir);
+       dput(new_odfdentry);
+
+out:
+       return err;
+}
+/*
  * Lookup an entry in the odf, and create it if necessary
  * Returns a an odf_dentry_info containing whiteout and
  * opaqueness information. Also handles hard links.
diff --git a/fs/unionfs/odf.h b/fs/unionfs/odf.h
index 7c2976e..1ec08bd 100644
--- a/fs/unionfs/odf.h
+++ b/fs/unionfs/odf.h
@@ -46,6 +46,8 @@ struct odf_dentry_info *odf_getns(void);
 struct odf_dentry_info *odf_fill_info(struct dentry *odf_dentry);
 void odf_put_info(struct odf_dentry_info *odi);
 
+int odf_rename(struct dentry *old_dentry, struct dentry *new_dentry);
+
 /* unlink */
 int odf_remove(struct dentry *dentry, int flags);
 int odf_reclaim(struct dentry *dentry);
diff --git a/fs/unionfs/rename.c b/fs/unionfs/rename.c
index 0044492..41a02ae 100644
--- a/fs/unionfs/rename.c
+++ b/fs/unionfs/rename.c
@@ -20,16 +20,13 @@
 
 static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
                     struct inode *new_dir, struct dentry *new_dentry,
-                    int bindex, struct dentry **wh_old)
+                    int bindex)
 {
        int err = 0;
        struct dentry *hidden_old_dentry;
        struct dentry *hidden_new_dentry;
        struct dentry *hidden_old_dir_dentry;
        struct dentry *hidden_new_dir_dentry;
-       struct dentry *hidden_wh_dentry;
-       struct dentry *hidden_wh_dir_dentry;
-       char *wh_name = NULL;
 
        hidden_new_dentry = unionfs_lower_dentry_idx(new_dentry, bindex);
        hidden_old_dentry = unionfs_lower_dentry_idx(old_dentry, bindex);
@@ -46,42 +43,6 @@ static int do_rename(struct inode *old_dir, struct dentry 
*old_dentry,
                }
        }
 
-       wh_name = alloc_whname(new_dentry->d_name.name, new_dentry->d_name.len);
-       if (IS_ERR(wh_name)) {
-               err = PTR_ERR(wh_name);
-               goto out;
-       }
-
-       hidden_wh_dentry = lookup_one_len(wh_name, hidden_new_dentry->d_parent,
-                               new_dentry->d_name.len + UNIONFS_WHLEN);
-       if (IS_ERR(hidden_wh_dentry)) {
-               err = PTR_ERR(hidden_wh_dentry);
-               goto out;
-       }
-
-       if (hidden_wh_dentry->d_inode) {
-               /* get rid of the whiteout that is existing */
-               if (hidden_new_dentry->d_inode) {
-                       printk(KERN_WARNING "Both a whiteout and a dentry"
-                                       " exist when doing a rename!\n");
-                       err = -EIO;
-
-                       dput(hidden_wh_dentry);
-                       goto out;
-               }
-
-               hidden_wh_dir_dentry = lock_parent(hidden_wh_dentry);
-               if (!(err = is_robranch_super(old_dentry->d_sb, bindex)))
-                       err = vfs_unlink(hidden_wh_dir_dentry->d_inode,
-                                              hidden_wh_dentry);
-
-               dput(hidden_wh_dentry);
-               unlock_dir(hidden_wh_dir_dentry);
-               if (err)
-                       goto out;
-       } else
-               dput(hidden_wh_dentry);
-
        dget(hidden_old_dentry);
        hidden_old_dir_dentry = dget_parent(hidden_old_dentry);
        hidden_new_dir_dentry = dget_parent(hidden_new_dentry);
@@ -92,26 +53,6 @@ static int do_rename(struct inode *old_dir, struct dentry 
*old_dentry,
        if (err)
                goto out_unlock;
 
-       /* ready to whiteout for old_dentry. caller will create the actual
-        * whiteout, and must dput(*wh_old)
-        */
-       if (wh_old) {
-               char *whname;
-               whname = alloc_whname(old_dentry->d_name.name,
-                                     old_dentry->d_name.len);
-               err = PTR_ERR(whname);
-               if (IS_ERR(whname))
-                       goto out_unlock;
-               *wh_old = lookup_one_len(whname, hidden_old_dir_dentry,
-                                        old_dentry->d_name.len + 
UNIONFS_WHLEN);
-               kfree(whname);
-               err = PTR_ERR(*wh_old);
-               if (IS_ERR(*wh_old)) {
-                       *wh_old = NULL;
-                       goto out_unlock;
-               }
-       }
-
        err = vfs_rename(hidden_old_dir_dentry->d_inode, hidden_old_dentry,
                         hidden_new_dir_dentry->d_inode, hidden_new_dentry);
 
@@ -131,8 +72,6 @@ out:
                        set_dbend(new_dentry, bindex);
        }
 
-       kfree(wh_name);
-
        return err;
 }
 
@@ -142,18 +81,16 @@ static int do_unionfs_rename(struct inode *old_dir,
                                   struct dentry *new_dentry)
 {
        int err = 0;
-       int bindex, bwh_old;
+       int bindex;
        int old_bstart, old_bend;
        int new_bstart, new_bend;
-       int do_copyup = -1;
+       int do_copyup = 0;
        struct dentry *parent_dentry;
        int local_err = 0;
        int eio = 0;
        int revert = 0;
-       struct dentry *wh_old = NULL;
 
        old_bstart = dbstart(old_dentry);
-       bwh_old = old_bstart;
        old_bend = dbend(old_dentry);
        parent_dentry = old_dentry->d_parent;
 
@@ -161,103 +98,47 @@ static int do_unionfs_rename(struct inode *old_dir,
        new_bend = dbend(new_dentry);
 
        /* Rename source to destination. */
-       err = do_rename(old_dir, old_dentry, new_dir, new_dentry, old_bstart,
-                       &wh_old);
+       err = do_rename(old_dir, old_dentry, new_dir, new_dentry, old_bstart);
+
        if (err) {
                if (!IS_COPYUP_ERR(err))
                        goto out;
-               do_copyup = old_bstart - 1;
+               do_copyup = 1;
        } else
                revert = 1;
 
-       /* Unlink all instances of destination that exist to the left of
-        * bstart of source. On error, revert back, goto out.
-        */
-       for (bindex = old_bstart - 1; bindex >= new_bstart; bindex--) {
-               struct dentry *unlink_dentry;
-               struct dentry *unlink_dir_dentry;
-
-               unlink_dentry = unionfs_lower_dentry_idx(new_dentry, bindex);
-               if (!unlink_dentry)
-                       continue;
-
-               unlink_dir_dentry = lock_parent(unlink_dentry);
-               if (!(err = is_robranch_super(old_dir->i_sb, bindex)))
-                       err = vfs_unlink(unlink_dir_dentry->d_inode,
-                                      unlink_dentry);
-
-               fsstack_copy_attr_times(new_dentry->d_parent->d_inode,
-                                    unlink_dir_dentry->d_inode);
-               /* propagate number of hard-links */
-               new_dentry->d_parent->d_inode->i_nlink =
-                   unionfs_get_nlinks(new_dentry->d_parent->d_inode);
-
-               unlock_dir(unlink_dir_dentry);
-               if (!err) {
-                       if (bindex != new_bstart) {
-                               dput(unlink_dentry);
-                               unionfs_set_lower_dentry_idx(new_dentry, 
bindex, NULL);
-                       }
-               } else if (IS_COPYUP_ERR(err)) {
-                       do_copyup = bindex - 1;
-               } else if (revert) {
-                       dput(wh_old);
+       if (do_copyup) {
+       
+               /* copyup branch 0 and try rename again */
+               bindex = 0;
+               err = copyup_dentry(old_dentry->d_parent->d_inode,
+                               old_dentry, old_bstart, bindex, NULL,
+                               old_dentry->d_inode->i_size);
+               if (!err)
+                       err = do_rename(old_dir, old_dentry, new_dir,
+                                       new_dentry, bindex);
+               if (err)
                        goto revert;
-               }
        }
 
-       if (do_copyup != -1) {
-               for (bindex = do_copyup; bindex >= 0; bindex--) {
-                       /* copyup the file into some left directory, so that
-                        * you can rename it
-                        */
-                       err = copyup_dentry(old_dentry->d_parent->d_inode,
-                                           old_dentry, old_bstart, bindex, 
NULL,
-                                           old_dentry->d_inode->i_size);
-                       if (!err) {
-                               dput(wh_old);
-                               bwh_old = bindex;
-                               err = do_rename(old_dir, old_dentry, new_dir,
-                                               new_dentry, bindex, &wh_old);
-                               break;
-                       }
-               }
-       }
+       /* if all ok, rename in odf */
+       err = odf_rename(old_dentry, new_dentry);
+       if (err) 
+               goto revert; 
 
-       /* make it opaque */
-       if (S_ISDIR(old_dentry->d_inode->i_mode)) {
-               err = make_dir_opaque(old_dentry, dbstart(old_dentry));
+       /* FIXME: when should we whiteout? */
+       if ((old_bstart != old_bend) || (do_copyup != -1)) {
+               err = odf_create_wh(old_dentry);
                if (err)
                        goto revert;
        }
 
-       /* Create whiteout for source, only if:
-        * (1) There is more than one underlying instance of source.
-        * (2) We did a copy_up
-        */
-       if ((old_bstart != old_bend) || (do_copyup != -1)) {
-               struct dentry *hidden_parent;
-               BUG_ON(!wh_old || wh_old->d_inode || bwh_old < 0);
-               hidden_parent = lock_parent(wh_old);
-               local_err = vfs_create(hidden_parent->d_inode, wh_old, S_IRUGO,
-                                      NULL);
-               unlock_dir(hidden_parent);
-               if (!local_err)
-                       set_dbopaque(old_dentry, bwh_old);
-               else {
-                       /* We can't fix anything now, so we cop-out and use 
-EIO. */
-                       printk(KERN_ERR "We can't create a whiteout for the "
-                                       "source in rename!\n");
-                       err = -EIO;
-               }
-       }
-
 out:
-       dput(wh_old);
        return err;
 
 revert:
        /* Do revert here. */
+       /* FIXME: revert odf also? only if create_wh_fails? */
        local_err = unionfs_refresh_hidden_dentry(new_dentry, old_bstart);
        if (local_err) {
                printk(KERN_WARNING "Revert failed in rename: the new refresh "
@@ -289,8 +170,7 @@ revert:
                goto revert_out;
        }
 
-       local_err = do_rename(new_dir, new_dentry, old_dir, old_dentry, 
old_bstart,
-                                       NULL);
+       local_err = do_rename(new_dir, new_dentry, old_dir, old_dentry, 
old_bstart);
 
        /* If we can't fix it, then we cop-out with -EIO. */
        if (local_err) {
@@ -311,40 +191,6 @@ revert_out:
        return err;
 }
 
-static struct dentry *lookup_whiteout(struct dentry *dentry)
-{
-       char *whname;
-       int bindex = -1, bstart = -1, bend = -1;
-       struct dentry *parent, *hidden_parent, *wh_dentry;
-
-       whname = alloc_whname(dentry->d_name.name, dentry->d_name.len);
-       if (IS_ERR(whname))
-               return (void *)whname;
-
-       parent = dget_parent(dentry);
-       unionfs_lock_dentry(parent);
-       bstart = dbstart(parent);
-       bend = dbend(parent);
-       wh_dentry = ERR_PTR(-ENOENT);
-       for (bindex = bstart; bindex <= bend; bindex++) {
-               hidden_parent = unionfs_lower_dentry_idx(parent, bindex);
-               if (!hidden_parent)
-                       continue;
-               wh_dentry = lookup_one_len(whname, hidden_parent,
-                                  dentry->d_name.len + UNIONFS_WHLEN);
-               if (IS_ERR(wh_dentry))
-                       continue;
-               if (wh_dentry->d_inode)
-                       break;
-               dput(wh_dentry);
-               wh_dentry = ERR_PTR(-ENOENT);
-       }
-       unionfs_unlock_dentry(parent);
-       dput(parent);
-       kfree(whname);
-       return wh_dentry;
-}
-
 /* We can't copyup a directory, because it may involve huge
  * numbers of children, etc.  Doing that in the kernel would
  * be bad, so instead we let the userspace recurse and ask us
@@ -377,7 +223,6 @@ int unionfs_rename(struct inode *old_dir, struct dentry 
*old_dentry,
                   struct inode *new_dir, struct dentry *new_dentry)
 {
        int err = 0;
-       struct dentry *wh_dentry;
 
        BUG_ON(!is_valid_dentry(old_dentry));
        BUG_ON(!is_valid_dentry(new_dentry));
@@ -396,14 +241,7 @@ int unionfs_rename(struct inode *old_dir, struct dentry 
*old_dentry,
        if (err)
                goto out;
 
-       /*
-        * if new_dentry is already hidden because of whiteout,
-        * simply override it even if the whiteouted dir is not empty.
-        */
-       wh_dentry = lookup_whiteout(new_dentry);
-       if (!IS_ERR(wh_dentry))
-               dput(wh_dentry);
-       else if (new_dentry->d_inode) {
+       if (new_dentry->d_inode) {
                if (S_ISDIR(old_dentry->d_inode->i_mode) !=
                    S_ISDIR(new_dentry->d_inode->i_mode)) {
                        err = S_ISDIR(old_dentry->d_inode->i_mode) ?
@@ -418,11 +256,6 @@ int unionfs_rename(struct inode *old_dir, struct dentry 
*old_dentry,
                        if (err)
                                goto out;
 
-                       if (!is_robranch(new_dentry))
-                               err = delete_whiteouts(new_dentry,
-                                                      dbstart(new_dentry),
-                                                      namelist);
-
                        free_rdstate(namelist);
 
                        if (err)
@@ -430,7 +263,6 @@ int unionfs_rename(struct inode *old_dir, struct dentry 
*old_dentry,
                }
        }
        err = do_unionfs_rename(old_dir, old_dentry, new_dir, new_dentry);
-
 out:
        if (err)
                /* clear the new_dentry stuff created */
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs

Reply via email to