commit e42950c9a6ba5e4d8b4899913826137abca3ed92
Author: Yiannis Pericleous <[EMAIL PROTECTED]>
Date:   Mon Feb 5 18:08:37 2007 -0500

    Basic whiteout functionality, rmdir moves dir to reclaim if logically empty

diff --git a/fs/unionfs/dirfops.c b/fs/unionfs/dirfops.c
index 6ff32a0..e6dc488 100644
--- a/fs/unionfs/dirfops.c
+++ b/fs/unionfs/dirfops.c
@@ -28,6 +28,7 @@ static void verify_rdstate_offset(struct unionfs_dir_state 
*rdstate)
 struct unionfs_getdents_callback {
        struct unionfs_dir_state *rdstate;
        void *dirent;
+       struct dentry *dir;
        int entries_written;
        int filldir_called;
        int filldir_error;
@@ -41,10 +42,24 @@ static int unionfs_filldir(void *dirent, const char *name, 
int namelen,
 {
        struct unionfs_getdents_callback *buf = dirent;
        struct filldir_node *found = NULL;
+       struct odf_dentry_info *odi = NULL;
        int err = 0;
        int is_wh_entry = 0;
+       int odf_flag = ODF_LOOKUP_FILE;
 
-       buf->filldir_called++;
+       buf->filldir_called++;  
+
+       /* odf check whiteouts */
+       if (d_type == DT_DIR)
+               odf_flag = ODF_LOOKUP_DIR;
+       odi = odf_lookup_name(buf->dir, name, namelen, odf_flag);
+       if (IS_ERR(odi)){
+               err = PTR_ERR(odi);
+               odi = NULL;
+               goto out;
+       }
+       if (odi && odi->whiteout)
+               goto out;
 
        if ((namelen > UNIONFS_WHLEN) &&
            !strncmp(name, UNIONFS_WHPFX, UNIONFS_WHLEN)) {
@@ -81,6 +96,8 @@ static int unionfs_filldir(void *dirent, const char *name, 
int namelen,
                buf->filldir_error = err;
 
 out:
+       if (odi)
+               odf_clear_info(odi);
        return err;
 }
 
@@ -130,6 +147,7 @@ static int unionfs_readdir(struct file *file, void *dirent, 
filldir_t filldir)
                buf.filldir_called = 0;
                buf.filldir_error = 0;
                buf.entries_written = 0;
+               buf.dir = file->f_dentry;
                buf.dirent = dirent;
                buf.filldir = filldir;
                buf.rdstate = uds;
diff --git a/fs/unionfs/dirhelper.c b/fs/unionfs/dirhelper.c
index bd15eb4..327e9bc 100644
--- a/fs/unionfs/dirhelper.c
+++ b/fs/unionfs/dirhelper.c
@@ -133,6 +133,7 @@ out:
 struct unionfs_rdutil_callback {
        int err;
        int filldir_called;
+       struct dentry *dir;
        struct unionfs_dir_state *rdstate;
        int mode;
 };
@@ -145,14 +146,25 @@ static int readdir_util_callback(void *dirent, const char 
*name, int namelen,
        struct unionfs_rdutil_callback *buf = dirent;
        int whiteout = 0;
        struct filldir_node *found;
+       struct odf_dentry_info *odi = NULL;
 
        buf->filldir_called = 1;
 
        if (name[0] == '.' && (namelen == 1 || (name[1] == '.' && namelen == 
2)))
                goto out;
 
+       /* check odf odf */
+       odi = odf_lookup_name(buf->dir, name, namelen, 0);
+       if (IS_ERR(odi)){
+               odi = NULL;
+               goto out;
+       }
+       if (odi && !odi->whiteout)
+               err = -ENOTEMPTY;
+       goto out; /* FIXME: bypass old code */
+
        if (namelen > UNIONFS_WHLEN &&
-           !strncmp(name, UNIONFS_WHPFX, UNIONFS_WHLEN)) {
+                       !strncmp(name, UNIONFS_WHPFX, UNIONFS_WHLEN)) {
                namelen -= UNIONFS_WHLEN;
                name += UNIONFS_WHLEN;
                whiteout = 1;
@@ -172,6 +184,8 @@ static int readdir_util_callback(void *dirent, const char 
*name, int namelen,
                               buf->rdstate->bindex, whiteout);
 
 out:
+       if (odi)
+               odf_clear_info(odi);
        buf->err = err;
        return err;
 }
@@ -243,6 +257,7 @@ int check_empty(struct dentry *dentry, struct 
unionfs_dir_state **namelist)
 
                do {
                        buf->filldir_called = 0;
+                       buf->dir = dentry;
                        buf->rdstate->bindex = bindex;
                        err = vfs_readdir(hidden_file,
                                          readdir_util_callback, buf);
diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
index 830a4e5..aec8f73 100644
--- a/fs/unionfs/lookup.c
+++ b/fs/unionfs/lookup.c
@@ -332,9 +332,6 @@ out_positive:
        dput(first_hidden_dentry);
        unionfs_mntput(first_dentry, first_dentry_offset);
 
-       /* check odf */
-       UNIONFS_D(dentry)->odf_info = odf_lookup(parent_dentry, dentry, 0);
-
        /* Partial lookups need to reinterpose, or throw away older negs. */
        if (lookupmode == INTERPOSE_PARTIAL) {
                if (dentry->d_inode) {
@@ -356,6 +353,14 @@ out_positive:
        if (err)
                goto out_drop;
 
+       /* check for whiteout */
+       if (UNIONFS_D(dentry)->odf_info) {
+               if (UNIONFS_D(dentry)->odf_info->whiteout){
+                       err = -ENOENT;
+                       goto out_drop;
+               }
+       }
+
        goto out;
 
 out_drop:
diff --git a/fs/unionfs/main.c b/fs/unionfs/main.c
index 6db077e..17029d0 100644
--- a/fs/unionfs/main.c
+++ b/fs/unionfs/main.c
@@ -73,7 +73,13 @@ int unionfs_interpose(struct dentry *dentry, struct 
super_block *sb, int flag)
                /* get unique inode number for unionfs */
                if ( !UNIONFS_D(dentry)->odf_info )
                        UNIONFS_D(dentry)->odf_info = 
-                               odf_lookup(dentry->d_parent, dentry, odf_flag);
+                               odf_lookup(dentry->d_parent, dentry, odf_flag | 
ODF_LOOKUP_RMV_WH);
+               if (IS_ERR(UNIONFS_D(dentry)->odf_info)){
+                       printk("unionfs_interpose: odf failed to create 
dentry\n");
+                       err = PTR_ERR(UNIONFS_D(dentry)->odf_info);
+                       goto out;
+               }
+               
                ino = UNIONFS_D(dentry)->odf_info->inum;
 
                inode = iget(sb, ino);
diff --git a/fs/unionfs/odf.c b/fs/unionfs/odf.c
index 4d27aa1..ecb1a4d 100644
--- a/fs/unionfs/odf.c
+++ b/fs/unionfs/odf.c
@@ -1,6 +1,5 @@
 #include "union.h"
 
-static int sss = 0;
 /*
  *     Initialize any odf data we might need
  */
@@ -65,30 +64,113 @@ out:
 }
 
 /*
+ *     Returns the dentry of /odf/reclaim
+ */
+struct odf_dentry_info* odf_getrc(void)
+{
+       struct nameidata nd;
+       struct odf_dentry_info* odi = NULL;
+       int err = 0;
+       
+       err = path_lookup(ODF_RC, LOOKUP_FOLLOW, &nd);  
+       if (err) {      
+               printk(KERN_WARNING "unionfs_odf: Invalid odf\n");
+               odi = ERR_PTR(err);
+               goto out;
+       }
+       odi = odf_fill_info(nd.dentry);
+       path_release(&nd);
+       
+out:
+       return odi;
+}
+
+int odf_reclaim_dir(struct dentry *dir)
+{
+       struct inode *old_dir, *new_dir;
+       struct dentry *old_dentry, *new_dentry;
+       struct odf_dentry_info *odi = odf_getrc();
+       char *new_name = NULL;
+       int err = 0;
+
+       if (IS_ERR(odi)){
+               err = PTR_ERR(odi);
+               odi = NULL;
+               goto out;
+       }
+       if (!odi){ /* Invalid ODF format(?) */
+               err = -EINVAL;
+               goto out;
+       }
+       new_name = kzalloc(ODF_INAME_LEN, GFP_KERNEL);
+       if (!new_name){
+               err = -ENOMEM;
+               goto out;
+       }
+       sprintf(new_name,"%lu", dir->d_inode->i_ino);   
+
+       old_dentry = dir;
+       old_dir = dir->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)){
+               err = PTR_ERR(odi);
+               goto out;
+       }
+       if(new_dentry->d_inode) {
+               /* FIXME: this should not happen */
+               printk(KERN_WARNING "odf_reclaim_dir: %s already exists in 
/odf/reclaim\n", new_name);
+       }
+       err = vfs_rename(old_dir, old_dentry, new_dir, new_dentry);
+       dput(new_dentry);
+out:
+       kfree(new_name);
+       if (odi)
+               odf_clear_info(odi);
+       return err;
+}
+
+/*
  *     Lookup an entry in the odf, create it if not found,
  *     else check for whiteouts
  *     Handle hard links
  */
 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);
+               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 dentry *odf_dentry = NULL;
        struct odf_dentry_info *odi = NULL;
        struct inode *odf_i_dir = UNIONFS_D(parent)->odf_info->dentry->d_inode;
        int err = 0;
 
-       if (UNIONFS_D(dentry)->odf_info) {
-               odf_clear_info(UNIONFS_D(dentry)->odf_info);
-               UNIONFS_D(dentry)->odf_info = NULL;
+       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 (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(dentry->d_name.name, 
-                               UNIONFS_D(parent)->odf_info->dentry,
-                               dentry->d_name.len);
-       
        /* create inode in odf if dont exist */
        /* XXX: 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 */
                if (flags & ODF_LOOKUP_FILE)
                        err = vfs_create(odf_i_dir, odf_dentry, S_IRWXUGO, 0 );
@@ -100,12 +182,14 @@ struct odf_dentry_info *odf_lookup(struct dentry *parent, 
struct dentry *dentry,
                        dput(odf_dentry);
                        goto out;
                }
+               if (err) {
+                       printk(KERN_WARNING "could not create odf dentry" );
+                       odi = ERR_PTR(err); 
+                       goto out;
+               }
                odf_set_opaque_i(odf_dentry->d_inode, -1);
                odf_set_wh_i(odf_dentry->d_inode,0);
                
-               /* XXX */
-               if (err)
-                       printk(KERN_WARNING "could not create odf dentry" );
        }
        else {
                /* FIXME check for whiteouts & hardlinks */
@@ -118,6 +202,36 @@ out:
        return odi;
 }
 
+/*
+ * Unlinks the file from odf if exist, creates a new file with
+ * the same name and sets its whiteout flag
+ */
+int odf_create_wh(struct dentry *dentry)
+{
+       int err = 0;
+       struct dentry *odf_dentry;
+
+       BUG_ON(!UNIONFS_D(dentry)->odf_info);
+
+       odf_dentry = UNIONFS_D(dentry)->odf_info->dentry;
+       
+       if (S_ISDIR(odf_dentry->d_inode->i_mode))
+               err = odf_reclaim_dir(odf_dentry);
+       else
+               err = vfs_unlink(odf_dentry->d_parent->d_inode, odf_dentry);
+       if (err)
+               goto out;
+       odf_clear_info(UNIONFS_D(dentry)->odf_info);
+       UNIONFS_D(dentry)->odf_info = NULL;
+       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;       
+       }
+       err = odf_set_wh(dentry,1);
+out:
+       return err;
+}
 
 /*
  * Sets the whiteout flag
@@ -125,7 +239,10 @@ out:
  */
 int odf_set_wh(struct dentry *dentry, int boolean)
 {
-       return odf_set_wh_i(UNIONFS_D(dentry)->odf_info->dentry->d_inode, 
boolean);
+       int err = odf_set_wh_i(UNIONFS_D(dentry)->odf_info->dentry->d_inode, 
boolean);
+       if (!err) 
+               UNIONFS_D(dentry)->odf_info->whiteout = boolean;
+       return err;
 }
 int odf_set_wh_i(struct inode *i, int boolean)
 {
@@ -148,7 +265,9 @@ int odf_is_wh(struct dentry *dentry)
 }
 int odf_is_wh_i(struct inode *i)
 {
-       return EXT2_I(i)->i_flags & ODF_WHITEOUT;
+       if (EXT2_I(i)->i_flags & ODF_WHITEOUT)
+               return 1;
+       return 0;
 }
 
 /*
@@ -163,7 +282,9 @@ int odf_is_opaque_i(struct inode *i)
 {
        if (!S_ISDIR(i->i_mode))
                return 0;
-       return EXT2_I(i)->i_flags & ODF_OPAQUE;
+       if (EXT2_I(i)->i_flags & ODF_OPAQUE)
+               return 1;
+       return 0;
 }
 /*
  * Gets opaque branch of a dentry, -1 if not opaque
@@ -192,7 +313,10 @@ int odf_get_opaque_i(struct inode *i)
  */
 int odf_set_opaque(struct dentry *dentry, int branch)
 {
-       return odf_set_opaque_i(UNIONFS_D(dentry)->odf_info->dentry->d_inode, 
branch);
+       int err = 
odf_set_opaque_i(UNIONFS_D(dentry)->odf_info->dentry->d_inode, branch);
+       if (!err)
+               UNIONFS_D(dentry)->odf_info->opaque = branch;
+       return err;
 }
 int odf_set_opaque_i(struct inode *i, int branch) 
 {
@@ -411,6 +535,8 @@ 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);
+       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);
diff --git a/fs/unionfs/odf.h b/fs/unionfs/odf.h
index 6d15dc7..bcd6b39 100644
--- a/fs/unionfs/odf.h
+++ b/fs/unionfs/odf.h
@@ -13,10 +13,12 @@
 /* Some string constants */
 #define ODF_BRANCH_PATH 255
 #define ODF_OPTIONS_LEN 255
+#define ODF_INAME_LEN  10
 
 /* Lookup flags (what to create if lookup fails) */
 #define ODF_LOOKUP_FILE        1 
-#define ODF_LOOKUP_DIR 2
+#define ODF_LOOKUP_DIR 2
+#define ODF_LOOKUP_RMV_WH 4
 
 /* Inode flags */ 
 #define ODF_WHITEOUT 0x01000000
@@ -33,6 +35,7 @@ int odf_putoptions(struct super_block* sb_union, struct 
unionfs_dentry_info *hid
 
 /* lookup */
 struct odf_dentry_info *odf_lookup(struct dentry *parent, struct dentry 
*dentry, int flags);
+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);
@@ -42,6 +45,7 @@ int odf_set_wh(struct dentry *dentry, int boolean);
 int odf_is_wh(struct dentry *dentry);
 int odf_set_wh_i(struct inode *i, int boolean);
 int odf_is_wh_i(struct inode *i);
+int odf_create_wh(struct dentry *dentry);
 
 /* opaque */
 int odf_is_opaque(struct dentry *dentry);
@@ -51,5 +55,4 @@ 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);
 
-
 #endif /* _ODF_H_ */
diff --git a/fs/unionfs/subr.c b/fs/unionfs/subr.c
index f0869c2..21a8e4a 100644
--- a/fs/unionfs/subr.c
+++ b/fs/unionfs/subr.c
@@ -37,7 +37,11 @@ int create_whiteout(struct dentry *dentry, int start)
        bend = dbend(dentry);
 
        /* odf whiteout */
-       odf_set_wh(dentry,1);
+       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   
*/
 
        /* create dentry's whiteout equivalent */
        name = alloc_whname(dentry->d_name.name, dentry->d_name.len);
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs

Reply via email to