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