commit c0367d499b36158ccf7e2a007a08f3e8a70dd0da
Author: Yiannis Pericleous <[EMAIL PROTECTED]>
Date:   Fri Apr 6 14:42:49 2007 -0400

    holding off hardlinks until jeffs path_lookup modifications, removed all 
nasty hardlink code

diff --git a/fs/unionfs/copyup.c b/fs/unionfs/copyup.c
index 82571d2..ce67381 100644
--- a/fs/unionfs/copyup.c
+++ b/fs/unionfs/copyup.c
@@ -435,8 +435,7 @@ 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); 
+       err = odf_copyup_link(sb, old_hidden_dentry, new_hidden_dentry, 
old_bindex, new_bindex);
 
        goto out_unlock;
        /****/
diff --git a/fs/unionfs/fanout.h b/fs/unionfs/fanout.h
index a570c19..43c73e1 100644
--- a/fs/unionfs/fanout.h
+++ b/fs/unionfs/fanout.h
@@ -55,6 +55,16 @@ static inline void new_branch_id(struct super_block *sb, int 
index)
        set_branch_id(sb, index, ++UNIONFS_SB(sb)->high_branch_id);
 }
 
+static inline int branch_id_to_idx(struct super_block *sb, int branch_id)
+{
+       int i;
+       for (i = 0; i < sbmax(sb); i++) {
+               if (UNIONFS_SB(sb)->data[i].branch_id == branch_id)
+                       return i;
+       }
+       return -1;
+}
+
 /* File to lower file. */
 static inline struct file *unionfs_lower_file(const struct file *f)
 {
diff --git a/fs/unionfs/odf.c b/fs/unionfs/odf.c
index 01df833..2b8db07 100644
--- a/fs/unionfs/odf.c
+++ b/fs/unionfs/odf.c
@@ -377,6 +377,129 @@ out:
        return err;
 }
 
+/* Adds a dirent to the inode's hardlink info file if it doesn't exist.
+ * If the file was empty, fills in the copyup info (branch and inum) with 0's
+ * If the file was not empty returns the odf dentry of one of the links for the
+ * odf to link to it. (We might need to store the odf inum parent as well)
+ */
+struct dentry *__link_add_dirent(struct file *link_file, struct dentry *dentry)
+{
+       int err = 0, len;
+       char *name = NULL;
+       loff_t size;
+       u64 ino;
+       mm_segment_t oldfs;
+       __le64 le64;
+       __le32 le32;
+
+       oldfs = get_fs();
+       set_fs(KERNEL_DS);
+       
+       size = i_size_read(link_file->f_dentry->d_inode);
+
+       
+       if (size == 0) {
+               /* file is new, fill in copyup info with 0's */
+               link_file->f_pos = 0;
+               le32 = 0;
+               err = link_file->f_op->write(link_file, (char*)&le32,
+                               sizeof(__le32), &link_file->f_pos);
+               if (err != sizeof(__le32)){
+                       err = -EIO;
+                       goto out;
+               }
+
+               le64 = 0;
+               err = link_file->f_op->write(link_file, (char*)&le64,
+                               sizeof(__le64), &link_file->f_pos);
+               if (err != sizeof(__le64)){
+                       err = -EIO;
+                       goto out;
+               }
+       }       
+       else {
+
+               /* check if our dirent is already in the file */
+               link_file->f_pos = sizeof(__le32) + sizeof(__le64);
+               
+               while (link_file->f_pos < size) {
+
+                       err = link_file->f_op->read(link_file, (char*)&le32,
+                               sizeof(__le32), &link_file->f_pos);
+                       if (err != sizeof(__le32)){
+                               err = -EIO;
+                               goto out;
+                       }
+                       len = le32_to_cpu(le32);
+
+                       kfree(name);
+                       name = kmalloc(len, GFP_KERNEL);
+                       if (!name) {
+                               err = -ENOMEM;
+                               goto out;
+                       }
+                       err = link_file->f_op->read(link_file, name,
+                                       len, &link_file->f_pos);
+                       if (err != sizeof(len)){
+                               err = -EIO;
+                               goto out;
+                       }
+
+                       err = link_file->f_op->read(link_file, (char*)&le64,
+                               sizeof(__le64), &link_file->f_pos);
+                       if (err != sizeof(__le64)){
+                               err = -EIO;
+                               goto out;
+                       }
+                       ino = le64_to_cpu(le64);
+                       
+                       /* check if this is our dirent */
+                       if (ino == dentry->d_parent->d_inode->i_ino &&
+                               dentry->d_name.len == len &&
+                               !strncmp(dentry->d_name.name, name, len)){
+                               err = 0;
+                               goto out;
+                       }
+               }
+
+       }
+
+       /* write the dirent in the file */
+       le32 = cpu_to_le32(dentry->d_name.len);
+       err = link_file->f_op->write(link_file, (char*)&le32,
+                       sizeof(__le32), &link_file->f_pos);
+       if (err != sizeof(__le32)){
+               err = -EIO;
+               goto out;
+       }
+
+       err = link_file->f_op->write(link_file, dentry->d_name.name,
+                       dentry->d_name.len, &link_file->f_pos);
+       if (err != dentry->d_name.len){
+               err = -EIO;
+               goto out;
+       }
+
+       le64 = cpu_to_le64(dentry->d_parent->d_inode->i_ino);
+       err = link_file->f_op->write(link_file, (char*)&le64,
+                       sizeof(__le64), &link_file->f_pos);
+       if (err != sizeof(__le64)){
+               err = -EIO;
+               goto out;
+       }
+       err = 0;
+out:
+       set_fs(oldfs);
+       kfree(name);
+       if (err)
+               return ERR_PTR(err);
+       return NULL;
+}
+
+/* 
+ * Update the original inode's copyup info in the link file, and then for each 
entry
+ * in the file, create parent hierarchies in the copied up branch and link to 
the new_dentry
+ */
 int odf_copyup_link(struct super_block *sb, struct dentry *old_dentry, struct 
dentry *new_dentry,
                        int old_branch, int new_branch)
 {
@@ -386,11 +509,11 @@ int odf_copyup_link(struct super_block *sb, struct dentry 
*old_dentry, struct de
        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));
+       /* do nothing if this has no links? or should we actually check if it 
has a link file? */
        if (old_dentry->d_inode->i_nlink <= 1)
                return 0;
        
@@ -430,73 +553,38 @@ int odf_copyup_link(struct super_block *sb, struct dentry 
*old_dentry, struct de
 
        /* 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));
+       if (err != sizeof(__le32)) {
+               err = -EIO;
+               set_fs(oldfs);
+               goto out;
+       }
 
        /* 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));
+       if (err != sizeof(__le64)) {
+               err = -EIO;
+               set_fs(oldfs);
+               goto out;
+       }
        
+       set_fs(oldfs);
+       err = 0;        
        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));
+       /* XXX: create parent hierarchies in new_branch for all other links 
+        *      and link to the new_dentry
+        */
 
-       err = 0;        
-       set_fs(oldfs);
 out:
        if (link_file)
                filp_close(link_file, NULL);
@@ -505,41 +593,150 @@ out:
        return err;
 }
 
-int __check_link_copyup(struct file *link_file)
+/* Checks the link file if the hard link was copied up, and if yes tries to 
link to the
+ * copied up inode in the copied up branch.
+ */
+int __check_link_copyup(struct file *link_file, struct dentry *dentry, int 
branch_src)
 {
-       int err, bid;
+       struct dentry *lower_dentry;
+       int err, bid = -1;
+       int branch_dst, dst_ro = 0;
        __le64 le64;
        __le32 le32;
-       u64 ino, cp_ino;
+       u64 ino = 0;
        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*)&le32,
+                               sizeof(__le32), &link_file->f_pos);
+       if (err == sizeof(__le32))
+               bid = le32_to_cpu(le32);
+       else if (err == 0)
+               goto skip;
+       else {
+               err = -EIO;
+               goto out_fs;
+       }
+
        err = link_file->f_op->read(link_file, (char*)&le64,
                                sizeof(__le64), &link_file->f_pos);
-       if (err != sizeof(__le64))
-               ino = 0;
-       else
+       if (err == sizeof(__le64))
                ino = le64_to_cpu(le64);
+       else if (err != 0) {
+               err = -EIO;
+               goto out_fs;
+       }
+skip:
+       set_fs(oldfs);
+       err = 0;
 
-       err = link_file->f_op->read(link_file, (char*)&le32,
+       /* check if there was no coypup */
+       if (!ino)
+               goto out;
+
+       /* XXX: the copied up file might have been copied up again, so we
+        *      need to check that too in order to find the final dst branch
+        */
+
+       /* get the branch numbers for cpd up branch and src branch */
+       BUG_ON(bid < 0);
+       branch_dst = branch_id_to_idx(dentry->d_sb, bid);
+       if (branch_dst >= 0)
+               dst_ro = is_robranch_super(dentry->d_sb, branch_dst);
+
+       odf_lock(UNIONFS_D(dentry->d_parent)->odf_info);
+
+       /* case 0:
+        * - dest branch id has changed because of remounts
+        * - do not copyup, remove copyup info from link info file 
+        */
+       if (branch_dst == -1) {
+               oldfs = get_fs();
+               set_fs(KERNEL_DS);
+
+               link_file->f_pos = 0;
+               le32 = 0;
+               err = link_file->f_op->write(link_file, (char*)&le32,
                                sizeof(__le32), &link_file->f_pos);
-       if (err != sizeof(__le32))
-               bid = -1;
-       else
-               bid = le32_to_cpu(le32);
+               if (err != sizeof(__le32)){
+                       set_fs(oldfs);
+                       err = -EIO;
+                       goto out_unlock;
+               }
 
-       err = link_file->f_op->read(link_file, (char*)&le64,
+               le64 = 0;
+               err = link_file->f_op->write(link_file, (char*)&le64,
                                sizeof(__le64), &link_file->f_pos);
-       if (err != sizeof(__le64))
-               cp_ino = 0;
-       else
-               cp_ino = le64_to_cpu(le64);
+               if (err != sizeof(__le64)){
+                       set_fs(oldfs);
+                       err = -EIO;
+                       goto out_unlock;
+               }
+               
+               set_fs(oldfs);
+               err = 0;
+       }
+
+       /* case 1:
+        * - Normal case, dst to the left of src and not ro
+        * - create parent hierarchy and link in the dst branch
+        */
+       else if (branch_dst < branch_src && !dst_ro) {
+
+               /* create parent hierarchy, then link */
+               BUG_ON(unionfs_lower_dentry_idx(dentry, branch_dst));
+
+               verify_locked(dentry->d_parent);
+               unionfs_unlock_dentry(dentry->d_parent); /*XXX: this is VERY 
nasty */
+               lower_dentry = create_parents(dentry->d_parent->d_inode,
+                                               dentry, branch_dst);
+               unionfs_lock_dentry(dentry->d_parent);
+
+               if (!lower_dentry || IS_ERR(lower_dentry)) {
+                       if (IS_ERR(lower_dentry))
+                               err = PTR_ERR(lower_dentry);
+                       goto out_unlock;
+               }
+               /* now link */  
+       }
+
+       /* case 2:
+        * - dst is the same as src branch and not ro
+        * - unlink old file and straight link with copied up
+        */
+       else if (branch_dst == branch_src && !dst_ro) {
+               ;
+       }
 
+       /* case 3:
+        * - dst to the right of src, because of moving branches, so if the 
file was already
+        *   copied up before the branch manip. it would now be hidden by the 
old non-cpied up
+        *   version of the file.
+        * - Do nothing!
+        */
+       else if (branch_dst < branch_src) {
+               ;
+       }
+
+       /* case 4:
+        * - dst branch is ro
+        * - copyup again!
+        */
+       else if (dst_ro) {
+               ;
+       }
+
+
+out_unlock:
+       odf_unlock(UNIONFS_D(dentry->d_parent)->odf_info);
+       goto out;
+out_fs:
        set_fs(oldfs);
-       return 0;
+out:
+       return err;
 }
 
 /*
@@ -566,9 +763,6 @@ int odf_lookup(struct dentry *parent, struct dentry 
*dentry, int flags)
        struct file *link_file = NULL;
        char *name, *uuid;
        int bstart, err = 0;
-       __le64 le64;
-       u64 ino = 0;
-       mm_segment_t oldfs;
 
        /* this might be called before interpose */
        if (dbstart(dentry) == dbend(dentry) && dbstart(dentry) == 0) {
@@ -615,29 +809,14 @@ int odf_lookup(struct dentry *parent, struct dentry 
*dentry, int flags)
                        mntput(osi->mnt);
                        goto out;
                }
-       
-               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);
-               set_fs(oldfs);
-               if (err < 0)
-                       goto out;
-               if(err == sizeof(__le64))
-                       ino = le64_to_cpu(le64);
-               else if (err == 0)
-                       ino = 0;
-               else {
-                       err = -EIO;
-                       goto out;
-               }
-               err = 0;
 
                /* check if link was copied up and act appropriately */
-               if (ino)
-                       __check_link_copyup(link_file);
+
+               /* XXX: Leave this out until Jeff's modifications to 
path_lookup 
+               __check_link_copyup(link_file, dentry, bstart);
+               __link_add_dirent(link_file, dentry);
                flags |= ODF_LOOKUP_LINK;
+               */
        }
 
        UNIONFS_D(dentry)->odf_info = __odf_lookup(
@@ -647,7 +826,7 @@ int odf_lookup(struct dentry *parent, struct dentry 
*dentry, int flags)
                                dentry->d_name.len,
                                flags,
                                UNIONFS_D(dentry)->odf_info,
-                               ino);
+                               NULL);
        if (IS_ERR(UNIONFS_D(dentry)->odf_info)){
                err = PTR_ERR(UNIONFS_D(dentry)->odf_info);
                UNIONFS_D(dentry)->odf_info = NULL;
@@ -656,19 +835,6 @@ int odf_lookup(struct dentry *parent, struct dentry 
*dentry, int flags)
        else if (UNIONFS_D(dentry)->odf_info == NULL)
                goto out;
 
-       /* if link file did not have the ino, write it */
-       if (link_file && !ino) {
-               oldfs = get_fs();
-               set_fs(KERNEL_DS);
-               link_file->f_pos = 0;
-               le64 = 
cpu_to_le64(UNIONFS_D(dentry)->odf_info->dentry->d_inode->i_ino);
-               err = link_file->f_op->write(link_file, (char*)&le64,
-                       sizeof(__le64), &link_file->f_pos);
-               set_fs(oldfs);  /* XXX check errors, and for -ENOSPC */
-               BUG_ON(err != sizeof(__le64));
-               err = 0;
-       }
-       
 out:
        odf_put_info(links);
        if (link_file)
@@ -679,9 +845,9 @@ out:
 struct odf_dentry_info *__odf_lookup(struct odf_sb_info *osi,
                        struct odf_dentry_info *parent,
                        const char *name, int len, int flags,
-                       struct odf_dentry_info *old_odi, u64 ino)
+                       struct odf_dentry_info *old_odi, 
+                       struct dentry *link)
 {
-       struct inode *i;
        struct dentry *odf_dentry;
        struct odf_dentry_info *odi = old_odi;
        struct inode *odf_i_dir = parent->dentry->d_inode;
@@ -733,12 +899,9 @@ retry:
                else if (cleaned)
                        odf_lock(osi->odi_ic);
 
-               if (ino && (flags & (ODF_LOOKUP_FILE | ODF_LOOKUP_LINK))) {
-                       /* if link ino was set in the file, link to that */
-                       i = iget(odf_dentry->d_sb, ino);
-                       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 */
+               if (link && (flags & (ODF_LOOKUP_FILE | ODF_LOOKUP_LINK))) {
+                       /* link to the given dentry */
+                       vfs_link(link, parent->dentry->d_inode, odf_dentry);
                }
                else if (flags & ODF_LOOKUP_FILE || flags & ODF_LOOKUP_WH) {
                        current->fsuid = 0;
@@ -795,20 +958,8 @@ retry:
                __odf_set_wh(odf_dentry->d_inode,whiteout);
        }
        else {
-               /* handle hardlinks, 3 cases:
-                *  1) ino in linkfile and odf_dentry are the same: all ok
-                *  2) ino in linkfile is not set: set it to odf_dentry's ino
-                *  3) ino in linkfile and odf_dentry are different: bad
-                */
-
-               /* case 3: unlink odf file and link to given ino */
-               if ((flags & ODF_LOOKUP_LINK) && 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);
-                       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);
-               }
+               /* hardlinks, check if link inode is same as odf_dentry inode,
+                  and if not, link them */
        }
 
        odi = odf_fill_info(old_odi, osi, odf_dentry);
@@ -1192,17 +1343,14 @@ int odf_get_opaque(struct super_block *sb, struct 
dentry *dentry)
        if (opaque == -1)
                return -1;
 
-       /* now check all branches for the branch id */
-       for (i = 0; i < sbmax(sb); i++) {
-               if (branch_id(sb, i) == opaque)
-                       return i;
-       }
+       i = branch_id_to_idx(sb, opaque);
 
        /* if this is reached then the opaque branch was deleted, so dentry
         * can no longer be considered opaque
         */
-       odf_set_opaque(dentry, -1);
-       return -1;
+       if (i == -1)
+               odf_set_opaque(dentry, -1);
+       return i;
 }
 
 int __odf_is_opaque(struct inode *i) 
@@ -1711,19 +1859,19 @@ void __odf_cleanup(void *args)
        if (cl->force) {
                cl->force = 0;
                cleanup = ODF_CLEAN_CACHE;
-               printk("unionfs cleanup thread: forced cleanup\n");
+//             printk("unionfs cleanup thread: forced cleanup\n");
        }
        else if (stat.f_bavail * 100 < stat.f_blocks * (100 - 
cl->attr->thresh_b->val)) {
                cleanup = ODF_CLEAN_BLOCKS;
                size =  stat.f_blocks * (100 - cl->attr->thresh_b->val) -
                                (stat.f_bavail * 100);
-               printk("unionfs cleanup thread: free blocks below critical 
size\n");
+//             printk("unionfs cleanup thread: free blocks below critical 
size\n");
        }
        else if (stat.f_ffree * 100 < stat.f_files * (100 - 
cl->attr->thresh_i->val)) {
                cleanup = ODF_CLEAN_INODES;
                size = stat.f_files * (100 - cl->attr->thresh_i->val) -
                                (stat.f_ffree * 100);
-               printk("unionfs cleanup thread: free inodes below critical 
size\n");
+//             printk("unionfs cleanup thread: free inodes below critical 
size\n");
        }
        if (cleanup)
                err = odf_cleanup(cl->odf, cleanup, size);
diff --git a/fs/unionfs/odf.h b/fs/unionfs/odf.h
index ed0bba5..8126cc5 100644
--- a/fs/unionfs/odf.h
+++ b/fs/unionfs/odf.h
@@ -67,12 +67,13 @@ static inline char *odf_get_branch_uuid(struct odf_sb_info 
*odf, int branch)
 /* lookup */
 int odf_lookup(struct dentry *parent, struct dentry *dentry, int flags);
 struct odf_dentry_info *__odf_lookup(struct odf_sb_info *osi, struct 
odf_dentry_info *parent,
-               const char *name, int len, int flags, struct odf_dentry_info 
*old_odi, u64 ino);
+               const char *name, int len, int flags, struct odf_dentry_info 
*old_odi,
+               struct dentry *link);
 static inline struct odf_dentry_info *odf_lookup_name(struct odf_sb_info *osi, 
                struct odf_dentry_info *parent, const char *name, int len, 
                int flags, struct odf_dentry_info *old_odi)
 {
-       return __odf_lookup(osi, parent, name, len, flags, old_odi, 0);
+       return __odf_lookup(osi, parent, name, len, flags, old_odi, NULL);
 }
 struct odf_dentry_info *odf_getpath(struct dentry *d_odf, struct odf_sb_info 
*osi, const char *name);
 struct odf_dentry_info *odf_fill_info(struct odf_dentry_info *odi,
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs

Reply via email to