commit 1ea2386bbaf70b3f6481dcd48f3f4026818b2017
Author: Yiannis Pericleous <[EMAIL PROTECTED]>
Date:   Thu Apr 5 06:25:39 2007 -0400

    save copyup dst and inode on copyup of hardlinks

diff --git a/fs/unionfs/copyup.c b/fs/unionfs/copyup.c
index 331c6ee..82571d2 100644
--- a/fs/unionfs/copyup.c
+++ b/fs/unionfs/copyup.c
@@ -435,6 +435,9 @@ static int copyup_named_dentry(struct inode *dir, struct 
dentry *dentry,
        if (!d_deleted(dentry))
                unionfs_reinterpose(dentry);
 
+       err = odf_copyup_link(sb, old_hidden_dentry, new_hidden_dentry,
+                                       old_bindex, new_bindex); 
+
        goto out_unlock;
        /****/
 
diff --git a/fs/unionfs/odf.c b/fs/unionfs/odf.c
index fb81d03..c53ed13 100644
--- a/fs/unionfs/odf.c
+++ b/fs/unionfs/odf.c
@@ -376,6 +376,172 @@ out_unlock:
 out:
        return err;
 }
+
+int odf_copyup_link(struct super_block *sb, struct dentry *old_dentry, struct 
dentry *new_dentry,
+                       int old_branch, int new_branch)
+{
+       char *name, *uuid;
+       struct odf_dentry_info *links = NULL;
+       struct odf_sb_info *osi = UNIONFS_SB(sb)->odf;
+       struct file *link_file = NULL;
+       mm_segment_t oldfs;
+       int err = 0;
+       u64 ino;
+       __le64 le64;
+       __le32 le32;
+       
+       BUG_ON(S_ISDIR(old_dentry->d_inode->i_mode));
+       if (old_dentry->d_inode->i_nlink <= 1)
+               return 0;
+       
+       name = kmalloc(UUID_LEN * 2 + 1,GFP_KERNEL);
+       if (!name) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       /* update the old link info file with the copyup info */
+       uuid = odf_get_branch_uuid(osi, old_branch);
+       sprintf(name,"%x%x%x%x", *(unsigned int *) uuid,
+                               *(unsigned int *) uuid + 4,
+                               *(unsigned int *) uuid + 8,
+                               *(unsigned int *) uuid + 12);
+       links = odf_ic_dentry(osi, old_dentry->d_inode->i_ino, name, 
strlen(name));
+       if (IS_ERR(links)) {
+               err = PTR_ERR(links);
+               links = NULL;
+               goto out;
+       }
+
+       /* open the file */
+       dget(links->dentry);
+       mntget(osi->mnt);
+       link_file = dentry_open(links->dentry, osi->mnt, O_RDWR);
+       if (IS_ERR(link_file)) {
+               err = PTR_ERR(link_file);
+               link_file = NULL;
+               dput(links->dentry);
+               mntput(osi->mnt);
+               goto out;
+       }
+       
+       oldfs = get_fs();
+       set_fs(KERNEL_DS);
+
+       /* get the odf ino first */
+       link_file->f_pos = 0;
+       err = link_file->f_op->read(link_file, (char*)&le64,
+                               sizeof(__le64), &link_file->f_pos);
+       if (err < 0)
+               goto out;
+       BUG_ON(err != sizeof(__le64));
+       ino = le64_to_cpu(le64);
+
+       /* write destination branch id*/        
+       le32 = cpu_to_le32(branch_id(sb, new_branch));
+       err = link_file->f_op->write(link_file, (char*)&le32,
+                               sizeof(__le32), &link_file->f_pos);
+       BUG_ON(err != sizeof(__le32));
+
+       /* write destination lower inode ino */
+       le64 = cpu_to_le64(new_dentry->d_inode->i_ino);
+       err = link_file->f_op->write(link_file, (char*)&le64,
+                               sizeof(__le64), &link_file->f_pos);
+       BUG_ON(err != sizeof(__le64));
+       
+       odf_put_info(links);
+       links = NULL;
+       filp_close(link_file, NULL);
+       link_file = NULL;
+
+       /* now update the destination link info file */
+       uuid = odf_get_branch_uuid(osi, new_branch);
+       sprintf(name,"%x%x%x%x", *(unsigned int *) uuid,
+                               *(unsigned int *) uuid + 4,
+                               *(unsigned int *) uuid + 8,
+                               *(unsigned int *) uuid + 12);
+       links = odf_ic_dentry(osi, new_dentry->d_inode->i_ino, name, 
strlen(name));
+       if (IS_ERR(links)) {
+               err = PTR_ERR(links);
+               links = NULL;
+               goto out;
+       }
+
+       /* open the file */
+       dget(links->dentry);
+       mntget(osi->mnt);
+       link_file = dentry_open(links->dentry, osi->mnt, O_RDWR);
+       if (IS_ERR(link_file)) {
+               err = PTR_ERR(link_file);
+               link_file = NULL;
+               dput(links->dentry);
+               mntput(osi->mnt);
+               goto out;
+       }
+       
+       link_file->f_pos = 0;
+       le64 = cpu_to_le64(ino);
+       err = link_file->f_op->write(link_file, (char*)&le64,
+                               sizeof(__le64), &link_file->f_pos);
+       BUG_ON(err != sizeof(__le64));
+
+       le32 = 0;
+       err = link_file->f_op->write(link_file, (char*)&le32,
+                               sizeof(__le32), &link_file->f_pos);
+       BUG_ON(err != sizeof(__le32));
+
+       le64 = 0;
+       err = link_file->f_op->write(link_file, (char*)&le64,
+                               sizeof(__le64), &link_file->f_pos);
+       BUG_ON(err != sizeof(__le64));
+
+       err = 0;        
+       set_fs(oldfs);
+out:
+       if (link_file)
+               filp_close(link_file, NULL);
+       odf_put_info(links);
+       kfree(name);
+       return err;
+}
+
+int __check_link_copyup(struct file *link_file)
+{
+       int err, bid;
+       __le64 le64;
+       __le32 le32;
+       u64 ino, cp_ino;
+       mm_segment_t oldfs;
+
+       oldfs = get_fs();
+       set_fs(KERNEL_DS);
+
+       link_file->f_pos = 0;
+       err = link_file->f_op->read(link_file, (char*)&le64,
+                               sizeof(__le64), &link_file->f_pos);
+       if (err != sizeof(__le64))
+               ino = 0;
+       else
+               ino = le64_to_cpu(le64);
+
+       err = link_file->f_op->read(link_file, (char*)&le32,
+                               sizeof(__le32), &link_file->f_pos);
+       if (err != sizeof(__le32))
+               bid = -1;
+       else
+               bid = le32_to_cpu(le32);
+
+       err = link_file->f_op->read(link_file, (char*)&le64,
+                               sizeof(__le64), &link_file->f_pos);
+       if (err != sizeof(__le64))
+               cp_ino = 0;
+       else
+               cp_ino = le64_to_cpu(le64);
+
+       set_fs(oldfs);
+       return 0;
+}
+
 /*
  * Lookup an entry in the odf, and create it if necessary
  * Returns a an odf_dentry_info containing whiteout and
@@ -446,7 +612,8 @@ int odf_lookup(struct dentry *parent, struct dentry 
*dentry, int flags)
                        goto out;
                }
        
-               /* check if link was copied up and act approprietely */
+               /* check if link was copied up and act appropriately */
+               __check_link_copyup(link_file);
        }
 
        UNIONFS_D(dentry)->odf_info = __odf_lookup(
@@ -475,7 +642,7 @@ struct odf_dentry_info *__odf_lookup(struct odf_sb_info 
*osi,
                        struct file *link_file)
 {
        struct inode *i;
-       struct dentry *odf_dentry, *d;
+       struct dentry *odf_dentry;
        struct odf_dentry_info *odi = old_odi;
        struct inode *odf_i_dir = parent->dentry->d_inode;
        int opaque, whiteout, err = 0, cleaned = 0;
@@ -496,7 +663,7 @@ struct odf_dentry_info *__odf_lookup(struct odf_sb_info 
*osi,
                err = link_file->f_op->read(link_file, (char*)&le64,
                                sizeof(__le64), &link_file->f_pos);
                set_fs(oldfs);
-               if (err<0) {
+               if (err < 0) {
                        odf_put_info(old_odi);
                        odi = ERR_PTR(err);
                        goto out;
@@ -551,10 +718,9 @@ retry:
                if (link_file && ino && (flags & ODF_LOOKUP_FILE)) {
                        /* if link ino was set in the file, link to that */
                        i = iget(odf_dentry->d_sb, ino);
-                       d = d_splice_alias(i, odf_dentry);
-                       iput(i);
-                       if (IS_ERR(d))
-                               err = PTR_ERR(d);
+                       BUG_ON(i == NULL || IS_ERR(i)); /*XXX: check for these 
*/
+                       BUG_ON(S_ISDIR(i->i_mode)); /* and also make sure the 
inode */
+                       d_add(odf_dentry, i); /* is not a new inode */
                }
                else if (flags & ODF_LOOKUP_FILE || flags & ODF_LOOKUP_WH) {
                        current->fsuid = 0;
@@ -621,16 +787,12 @@ retry:
                if (link_file && ino && ino != odf_dentry->d_inode->i_ino) {
                        vfs_unlink(odf_dentry->d_parent->d_inode, odf_dentry);
                        i = iget(odf_dentry->d_sb, ino);
-                       d = d_splice_alias(i, odf_dentry);
-                       iput(i);
-                       if (IS_ERR(d)) {
-                               odi = (struct odf_dentry_info *)d;
-                               odf_put_info(old_odi);
-                               goto out;
-                       }
+                       BUG_ON(i == NULL || IS_ERR(i)); /*XXX: check if i is 
the one */
+                       BUG_ON(S_ISDIR(i->i_mode));
+                       d_add(odf_dentry, i);
                }
        }
-       
+
        /* if link file did not have the ino, write it */
        if (link_file && !ino) {
                oldfs = get_fs();
@@ -643,7 +805,7 @@ retry:
                BUG_ON(err != sizeof(__le64));
                err = 0;
        }
-       
+
        odi = odf_fill_info(old_odi, osi, odf_dentry);
        dput(odf_dentry); /* since we dget in fill_info */
 out:
@@ -877,7 +1039,6 @@ out:
        return err;
 }
 
-
 /*
  * Unlinks the file from odf if exist, creates a new file with
  * the same name and sets its whiteout flag
diff --git a/fs/unionfs/odf.h b/fs/unionfs/odf.h
index 3c2d918..51acbb0 100644
--- a/fs/unionfs/odf.h
+++ b/fs/unionfs/odf.h
@@ -92,6 +92,9 @@ int odf_cache_dir(struct dentry *d_upper, struct dentry 
*d_odf, struct timespec
 int odf_rename(struct dentry *old_dentry, struct dentry *new_dentry);
 int odf_link(struct dentry *old_dentry, struct dentry *new_dentry);
 
+int odf_copyup_link(struct super_block *sb, struct dentry *old_dentry, struct 
dentry *new_dentry,
+                       int old_branch, int new_branch);
+
 /* unlink */
 int odf_remove(struct dentry *dentry, int flags);
 int odf_reclaim(struct dentry *dentry);
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs

Reply via email to