commit ef39c8489e656cb8ad28566e65a3dc5f8691c084
Author: Yiannis Pericleous <[EMAIL PROTECTED]>
Date:   Wed Feb 7 14:38:33 2007 -0500

    symlink, mknod to remove old whiteout
    
    removed some old unlink code
    new lookup flag to create dir as opaque
    some locking

diff --git a/fs/unionfs/dirfops.c b/fs/unionfs/dirfops.c
index 89387de..f17d4d0 100644
--- a/fs/unionfs/dirfops.c
+++ b/fs/unionfs/dirfops.c
@@ -96,8 +96,7 @@ static int unionfs_filldir(void *dirent, const char *name, 
int namelen,
                buf->filldir_error = err;
 
 out:
-       if (odi)
-               odf_clear_info(&odi);
+       odf_put_info(odi);
        return err;
 }
 
diff --git a/fs/unionfs/dirhelper.c b/fs/unionfs/dirhelper.c
index 3b43b79..afdb974 100644
--- a/fs/unionfs/dirhelper.c
+++ b/fs/unionfs/dirhelper.c
@@ -153,7 +153,7 @@ static int readdir_util_callback(void *dirent, const char 
*name, int namelen,
        if (name[0] == '.' && (namelen == 1 || (name[1] == '.' && namelen == 
2)))
                goto out;
 
-       /* check odf odf */
+       /* check odf */
        odi = odf_lookup_name(buf->dir, name, namelen, 0);
        if (IS_ERR(odi)){
                odi = NULL;
@@ -184,8 +184,7 @@ static int readdir_util_callback(void *dirent, const char 
*name, int namelen,
                               buf->rdstate->bindex, whiteout);
 
 out:
-       if (odi)
-               odf_clear_info(&odi);
+       odf_put_info(odi);
        buf->err = err;
        return err;
 }
diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
index 9a9687c..303ef86 100644
--- a/fs/unionfs/inode.c
+++ b/fs/unionfs/inode.c
@@ -192,7 +192,8 @@ static int unionfs_create(struct inode *parent, struct 
dentry *dentry,
                                break;
                } else {
                        UNIONFS_D(dentry)->odf_info =
-                               odf_lookup(dentry->d_parent, dentry, 
ODF_LOOKUP_FILE|ODF_LOOKUP_RMV_WH);
+                               odf_lookup(dentry->d_parent, dentry, 
+                               ODF_LOOKUP_FILE|ODF_LOOKUP_RMV_WH);
                        err = unionfs_interpose(dentry, parent->i_sb, 0);
                        if (!err) {
                                fsstack_copy_attr_times(parent,
@@ -470,6 +471,10 @@ static int unionfs_symlink(struct inode *dir, struct 
dentry *dentry,
                        if (!IS_COPYUP_ERR(err))
                                break;
                } else {
+                       /* update odf and remove any wh before interpose*/
+                       UNIONFS_D(dentry)->odf_info =
+                               odf_lookup(dentry->d_parent, dentry, 
+                               ODF_LOOKUP_FILE|ODF_LOOKUP_RMV_WH);
                        err = unionfs_interpose(dentry, dir->i_sb, 0);
                        if (!err) {
                                fsstack_copy_attr_times(dir,
@@ -704,6 +709,10 @@ static int unionfs_mknod(struct inode *dir, struct dentry 
*dentry, int mode,
                        unlock_dir(hidden_parent_dentry);
                        break;
                }
+               /* update odf and remove any wh before interpose*/
+               UNIONFS_D(dentry)->odf_info =
+                       odf_lookup(dentry->d_parent, dentry, 
+                       ODF_LOOKUP_FILE|ODF_LOOKUP_RMV_WH);
 
                err = unionfs_interpose(dentry, dir->i_sb, 0);
                if (!err) {
diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
index 91213bf..59532ee 100644
--- a/fs/unionfs/lookup.c
+++ b/fs/unionfs/lookup.c
@@ -448,7 +448,7 @@ void free_dentry_private_data(struct unionfs_dentry_info 
*udi)
 {
        if (!udi)
                return;
-       odf_clear_info(&udi->odf_info);
+       odf_put_info(udi->odf_info);
        kmem_cache_free(unionfs_dentry_cachep, udi);
 }
 
diff --git a/fs/unionfs/odf.c b/fs/unionfs/odf.c
index c7603ef..a864b96 100644
--- a/fs/unionfs/odf.c
+++ b/fs/unionfs/odf.c
@@ -112,13 +112,16 @@ int odf_reclaim(struct dentry *dentry)
        }
        sprintf(new_name,"%lu", dentry->d_inode->i_ino);        
 
+       /* lock new dir, the old dir should already be locked */
+       odf_lock(odi);
+       
        old_dentry = dentry;
        old_dir = dentry->d_parent->d_inode;
        new_dir = odi->dentry->d_inode;
        new_dentry = lookup_one_len(new_name, odi->dentry, strlen(new_name));
-       if(IS_ERR(new_dentry)){
+       if (IS_ERR(new_dentry)) {
                err = PTR_ERR(new_dentry);
-               goto out;
+               goto out_unlock;
        }
        
        /* this should never happen */
@@ -126,53 +129,71 @@ int odf_reclaim(struct dentry *dentry)
        
        err = vfs_rename(old_dir, old_dentry, new_dir, new_dentry);
        dput(new_dentry);
+
+out_unlock:
+       odf_unlock(odi); /* unlock new dir */
+
 out:
        kfree(new_name);
-       if (odi)
-               odf_clear_info(&odi);
+       odf_put_info(odi);
        return err;
 }
 
 /*
- *     Lookup an entry in the odf, create it if not found,
- *     else check for whiteouts
- *     Handle hard links
+ * 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.
+ * If no flags are set and lookup fails, NULL is returned
+ * The function puts the dentry's odf_info and NULL's it
+ * Flags:
+ *     - None set: lookup does not create any new entries
+ *     - ODF_LOOKUP_FILE: create a file entry if lookup fails
+ *     - ODF_LOOKUP_DIR: create a dir if lookup fails
+ *     - ODF_LOOKUP_RMV_WH: if lookup returns a wh, remove it
+ *             (useful for create where we want to rmv wh's)
+ *     - ODF_LOOKUP_OPQ: if a dir is created, set it opaque (branch 0)
  */
 struct odf_dentry_info *odf_lookup(struct dentry *parent, struct dentry 
*dentry, int flags)
 {      
-       if (UNIONFS_D(dentry)->odf_info)
-               odf_clear_info(&UNIONFS_D(dentry)->odf_info);
-
+       odf_put_info(UNIONFS_D(dentry)->odf_info);
+       UNIONFS_D(dentry)->odf_info = NULL;
        return odf_lookup_name(parent, dentry->d_name.name, dentry->d_name.len, 
flags);
 }
-struct odf_dentry_info *odf_lookup_name(struct dentry *parent, const char 
*name, int len, int flags)
+
+struct odf_dentry_info *odf_lookup_name(struct dentry *parent, const char 
*name, 
+                                                               int len, int 
flags)
 {
-       struct dentry *odf_dentry = NULL;
+       struct dentry *odf_dentry;
        struct odf_dentry_info *odi = NULL;
        struct inode *odf_i_dir = UNIONFS_D(parent)->odf_info->dentry->d_inode;
        int err = 0;
        
-       odf_dentry = lookup_one_len(name, UNIONFS_D(parent)->odf_info->dentry, 
len);
+       odf_dentry = lookup_one_len(name, 
+                       UNIONFS_D(parent)->odf_info->dentry, len);
        
        /* if create flags are set, remove existing whiteout */
-       if (!IS_ERR(odf_dentry) && odf_dentry->d_inode && (flags & 
ODF_LOOKUP_RMV_WH))
+       if (!IS_ERR(odf_dentry) 
+               && odf_dentry->d_inode 
+               && (flags & ODF_LOOKUP_RMV_WH)) 
        {
                if (odf_is_wh_i(odf_dentry->d_inode)){
                        vfs_unlink(odf_i_dir, odf_dentry);
                        dput(odf_dentry);
-                       /* does this make sense? */
-                       odf_dentry = lookup_one_len(name, 
UNIONFS_D(parent)->odf_info->dentry, len);
+                       odf_dentry = lookup_one_len(name,
+                               UNIONFS_D(parent)->odf_info->dentry, len);
                }
        }
 
        /* create inode in odf if dont exist */
-       /* XXX: should we fail if res is ERR? */
+       /* FIXME: should we fail if res is ERR? */
        if (IS_ERR(odf_dentry) || !odf_dentry->d_inode) {
                
                if (name[0]=='.')
                        BUG_ON(len==1 || (name[1]=='.'&&len==2));
        
                /* FIXME need to check hardlinks before create */
+               odf_lock(UNIONFS_D(parent)->odf_info); /* lock parent */
+
                if (flags & ODF_LOOKUP_FILE)
                        err = vfs_create(odf_i_dir, odf_dentry, S_IRWXUGO, 0 );
 
@@ -181,19 +202,24 @@ struct odf_dentry_info *odf_lookup_name(struct dentry 
*parent, const char *name,
 
                else {
                        dput(odf_dentry);
+                       odf_unlock(UNIONFS_D(parent)->odf_info);
                        goto out;
                }
                if (err) {
-                       printk(KERN_WARNING "could not create odf dentry" );
+                       printk(KERN_WARNING "odf_lookup: could not create odf 
dentry" );
                        odi = ERR_PTR(err); 
                        goto out;
                }
-               odf_set_opaque_i(odf_dentry->d_inode, -1);
+
+               odf_unlock(UNIONFS_D(parent)->odf_info);
+       
+               /* set opaqueness to 0 or -1 */
+               odf_set_opaque_i(odf_dentry->d_inode,
+                               -!(flags & ODF_LOOKUP_OPQ));
                odf_set_wh_i(odf_dentry->d_inode,0);
-               
        }
        else {
-               /* FIXME check for whiteouts & hardlinks */
+               /* FIXME check for hardlinks */
        }
        
        odi = odf_fill_info(odf_dentry);
@@ -216,16 +242,18 @@ int odf_create_wh(struct dentry *dentry)
        odf_dentry = UNIONFS_D(dentry)->odf_info->dentry;
        if (odf_is_wh_i(odf_dentry->d_inode))
                goto out;       /* nothing to be done */        
-
+       
        /* remove entry if existed */
        err = odf_remove(dentry, ODF_RMV_ANY);
        if (err)
                goto out;
 
-       odf_clear_info(&UNIONFS_D(dentry)->odf_info);
+       odf_put_info(UNIONFS_D(dentry)->odf_info);
 
        /* now create a new file and make it a whiteout */
-       UNIONFS_D(dentry)->odf_info = odf_lookup(dentry->d_parent, dentry, 
ODF_LOOKUP_FILE);
+       UNIONFS_D(dentry)->odf_info = 
+                       odf_lookup(dentry->d_parent, 
+                       dentry, ODF_LOOKUP_FILE);
        if (!UNIONFS_D(dentry)->odf_info){
                err = PTR_ERR(UNIONFS_D(dentry)->odf_info); /* odf out of 
space? */
                goto out;       
@@ -244,11 +272,12 @@ out:
  */
 int odf_remove(struct dentry *dentry, int flags)
 {
+       struct odf_dentry_info *odf_dir;
        struct odf_dentry_info *odi = NULL;
        int err = 0, rmv = 0;
 
        BUG_ON(!UNIONFS_D(dentry)->odf_info);
-
+       
        /* refresh odi */
        UNIONFS_D(dentry)->odf_info = odf_lookup(dentry->d_parent, dentry, 0);
        odi =  UNIONFS_D(dentry)->odf_info;
@@ -270,6 +299,9 @@ int odf_remove(struct dentry *dentry, int flags)
 
        if (!rmv)
                goto out;
+       
+       odf_dir = UNIONFS_D(dentry->d_parent)->odf_info;
+       odf_lock(odf_dir);
 
        /* remove */
        if (S_ISDIR(odi->dentry->d_inode->i_mode))
@@ -277,19 +309,22 @@ int odf_remove(struct dentry *dentry, int flags)
        else
                err = vfs_unlink(odi->dentry->d_parent->d_inode, odi->dentry);
        if (err)
-               goto out;
+               goto out_unlock;
 
        /* clean up */
-       odf_clear_info(&UNIONFS_D(dentry)->odf_info);
+       odf_put_info(UNIONFS_D(dentry)->odf_info);
 
+out_unlock:
+       odf_unlock(odf_dir);
 out:
        return err;
 }
 
 /*
- * Sets the whiteout flag
+ * Sets the whiteout flag, the boolean decides whether to set whiteout on/off
  * The dentry version takes a UnionFS dentry, the inode one an ODF inode
  */
+/* FIXME: for the following functions can we count on EXT2 to do the locking? 
*/
 int odf_set_wh(struct dentry *dentry, int boolean)
 {
        int err = odf_set_wh_i(UNIONFS_D(dentry)->odf_info->dentry->d_inode, 
boolean);
@@ -303,7 +338,7 @@ int odf_set_wh_i(struct inode *i, int boolean)
        if (boolean)
                EXT2_I(i)->i_flags |= ODF_WHITEOUT;
        else
-               EXT2_I(i)->i_flags &= !ODF_WHITEOUT;
+               EXT2_I(i)->i_flags &= ~ODF_WHITEOUT;
        err = ext2_write_inode(i, 1);
        return err;
 }
@@ -366,18 +401,19 @@ int odf_get_opaque_i(struct inode *i)
  */
 int odf_set_opaque(struct dentry *dentry, int branch)
 {
-       int err = 
odf_set_opaque_i(UNIONFS_D(dentry)->odf_info->dentry->d_inode, branch);
+       struct odf_dentry_info *odi = UNIONFS_D(dentry)->odf_info;
+       int err = odf_set_opaque_i(odi->dentry->d_inode, branch);
        if (!err)
-               UNIONFS_D(dentry)->odf_info->opaque = branch;
+               odi->opaque = branch;
        return err;
 }
+
 int odf_set_opaque_i(struct inode *i, int branch) 
 {
        u32 b = branch;
        int err = 0;
-
        if (branch < 0)
-               EXT2_I(i)->i_flags &= !ODF_OPAQUE;
+               EXT2_I(i)->i_flags &= ~ODF_OPAQUE;
        else {
                b <<= ODF_OPQ_BASE + 1;
                b >>= 1;
@@ -388,7 +424,7 @@ int odf_set_opaque_i(struct inode *i, int branch)
 }
 
 /* 
- *     returns the dirs= part of the mount options 
+ * returns the dirs= part of the mount options 
  */
 char *odf_getoptions(void)
 {
@@ -587,25 +623,26 @@ out:
  */
 struct odf_dentry_info *odf_fill_info(struct dentry *odf_dentry)
 {
-       struct odf_dentry_info *odi = kzalloc(sizeof(struct 
odf_dentry_info),GFP_KERNEL);
+       struct odf_dentry_info *odi = 
+                       kzalloc(sizeof(struct odf_dentry_info),GFP_KERNEL);
        odi->whiteout = odf_is_wh_i(odf_dentry->d_inode);
        odi->opaque = odf_get_opaque_i(odf_dentry->d_inode);
        odi->dentry = odf_dentry;
        odi->inum = odf_dentry->d_inode->i_ino;
        dget(odf_dentry);
+       mutex_init(&odi->lock);
        return odi;
 }
 
 /* 
  * Clears the odf_info data 
  */
-void odf_clear_info(struct odf_dentry_info **odi)
+void odf_put_info(struct odf_dentry_info *odi)
 {
-       if (!(*odi))
+       if (!odi)
                return;
-       dput((*odi)->dentry);
-       kfree(*odi);
-       *odi = NULL;
+       dput(odi->dentry);
+       kfree(odi);
 }
 
 
diff --git a/fs/unionfs/odf.h b/fs/unionfs/odf.h
index 2fc01fd..004ebe2 100644
--- a/fs/unionfs/odf.h
+++ b/fs/unionfs/odf.h
@@ -19,6 +19,7 @@
 #define ODF_LOOKUP_FILE        1 
 #define ODF_LOOKUP_DIR 2
 #define ODF_LOOKUP_RMV_WH 4
+#define ODF_LOOKUP_OPQ 8
 
 /* Unlink/Remove flags */
 #define ODF_RMV_WH 1
@@ -43,7 +44,7 @@ struct odf_dentry_info *odf_lookup(struct dentry *parent, 
struct dentry *dentry,
 struct odf_dentry_info *odf_lookup_name(struct dentry *parent, const char 
*name, int len, int flags);
 struct odf_dentry_info *odf_getns(void);
 struct odf_dentry_info *odf_fill_info(struct dentry *odf_dentry);
-void odf_clear_info(struct odf_dentry_info **odi);
+void odf_put_info(struct odf_dentry_info *odi);
 
 /* unlink */
 int odf_remove(struct dentry *dentry, int flags);
@@ -64,4 +65,16 @@ int odf_is_opaque_i(struct inode *i);
 int odf_get_opaque_i(struct inode *i);
 int odf_set_opaque_i(struct inode *i, int branch);
 
+/* Macros for locking an odf dentry info. */
+static inline void odf_lock(struct odf_dentry_info *odi)
+{
+        mutex_lock(&odi->lock);
+}
+
+static inline void odf_unlock(struct odf_dentry_info *odi)
+{
+        mutex_unlock(&odi->lock);
+}
+
+
 #endif /* _ODF_H_ */
diff --git a/fs/unionfs/subr.c b/fs/unionfs/subr.c
index e563bbc..8d1ce32 100644
--- a/fs/unionfs/subr.c
+++ b/fs/unionfs/subr.c
@@ -37,10 +37,7 @@ int create_whiteout(struct dentry *dentry, int start)
 
        /* odf whiteout */
        err = odf_create_wh(dentry);
-       if (err)
-               goto out;
-       else                    /*FIXME very creative and constructive if/else 
*/
-               goto out;       /*      to bypass the original whiteout code   
*/
+       goto out;               /* FIXME: bypass the original whiteout code   */
 
        /* create dentry's whiteout equivalent */
        name = alloc_whname(dentry->d_name.name, dentry->d_name.len);
diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
index 6256aa0..d62453d 100644
--- a/fs/unionfs/union.h
+++ b/fs/unionfs/union.h
@@ -92,6 +92,7 @@ struct odf_dentry_info {
         * the data in the odf file. Right now i keep a dentry for easy
         * lookup in the underlying ext2 
         */
+       struct mutex lock;
        u64 inum;
        int whiteout;
        int opaque;
diff --git a/fs/unionfs/unlink.c b/fs/unionfs/unlink.c
index dc846db..8224d11 100644
--- a/fs/unionfs/unlink.c
+++ b/fs/unionfs/unlink.c
@@ -18,57 +18,6 @@
 
 #include "union.h"
 
-/* unlink a file by creating a whiteout */
-static int unionfs_unlink_whiteout(struct inode *dir, struct dentry *dentry)
-{
-       struct dentry *hidden_dentry;
-       struct dentry *hidden_dir_dentry;
-       int bindex;
-       int err = 0;
-
-       if ((err = unionfs_partial_lookup(dentry)))
-               goto out;
-
-       bindex = dbstart(dentry);
-
-       hidden_dentry = unionfs_lower_dentry_idx(dentry, bindex);
-       if (!hidden_dentry)
-               goto out;
-
-       hidden_dir_dentry = lock_parent(hidden_dentry);
-
-       /* avoid destroying the hidden inode if the file is in use */
-       dget(hidden_dentry);
-       if (!(err = is_robranch_super(dentry->d_sb, bindex)))
-               err = vfs_unlink(hidden_dir_dentry->d_inode, hidden_dentry);
-       dput(hidden_dentry);
-       fsstack_copy_attr_times(dir, hidden_dir_dentry->d_inode);
-       unlock_dir(hidden_dir_dentry);
-
-       if (err && !IS_COPYUP_ERR(err))
-               goto out;
-
-       if (err) {
-               if (dbstart(dentry) == 0)
-                       goto out;
-
-               err = create_whiteout(dentry, dbstart(dentry) - 1);
-       } else if (dbopaque(dentry) != -1)
-               /* There is a hidden lower-priority file with the same name. */
-               err = create_whiteout(dentry, dbopaque(dentry));
-       else
-               err = create_whiteout(dentry, dbstart(dentry));
-
-out:
-       if (!err)
-               dentry->d_inode->i_nlink--;
-
-       /* We don't want to leave negative leftover dentries for revalidate. */
-       if (!err && (dbopaque(dentry) != -1))
-               update_bstart(dentry);
-
-       return err;
-}
 static int unionfs_do_unlink(struct inode *dir, struct dentry *dentry)
 {
        struct dentry *hidden_dentry;
@@ -128,7 +77,6 @@ int unionfs_unlink(struct inode *dir, struct dentry *dentry)
 
        unionfs_lock_dentry(dentry);
 
-       //err = unionfs_unlink_whiteout(dir, dentry);
        err = unionfs_do_unlink(dir, dentry);
        /* call d_drop so the system "forgets" about us */
        if (!err) {
@@ -145,38 +93,6 @@ int unionfs_unlink(struct inode *dir, struct dentry *dentry)
        return err;
 }
 
-static int unionfs_rmdir_first(struct inode *dir, struct dentry *dentry,
-                              struct unionfs_dir_state *namelist)
-{
-       int err;
-       struct dentry *hidden_dentry;
-       struct dentry *hidden_dir_dentry = NULL;
-
-       /* Here we need to remove whiteout entries. */
-       err = delete_whiteouts(dentry, dbstart(dentry), namelist);
-       if (err)
-               goto out;
-
-       hidden_dentry = unionfs_lower_dentry(dentry);
-
-       hidden_dir_dentry = lock_parent(hidden_dentry);
-
-       /* avoid destroying the hidden inode if the file is in use */
-       dget(hidden_dentry);
-       if (!(err = is_robranch(dentry)))
-               err = vfs_rmdir(hidden_dir_dentry->d_inode, hidden_dentry);
-       dput(hidden_dentry);
-
-       fsstack_copy_attr_times(dir, hidden_dir_dentry->d_inode);
-       /* propagate number of hard-links */
-       dentry->d_inode->i_nlink = unionfs_get_nlinks(dentry->d_inode);
-
-out:
-       if (hidden_dir_dentry)
-               unlock_dir(hidden_dir_dentry);
-       return err;
-}
-
 static int unionfs_do_rmdir(struct inode *dir, struct dentry *dentry)
 {
        struct dentry *hidden_dentry;
@@ -239,7 +155,6 @@ int unionfs_rmdir(struct inode *dir, struct dentry *dentry)
        if (err)
                goto out;
 
-//     err = unionfs_rmdir_first(dir, dentry, namelist);
        err = unionfs_do_rmdir(dir, dentry);
        if (err)
                goto out;
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs

Reply via email to