commit d2ebecb1718eb954412f91222f84ffefa15cbc07
Author: Yiannis Pericleous <[EMAIL PROTECTED]>
Date:   Sun Feb 4 15:09:12 2007 -0500

    initial odf mounting and somewhat persistent inodes

diff --git a/fs/unionfs/Makefile b/fs/unionfs/Makefile
index e6b2e0c..da2dc0c 100644
--- a/fs/unionfs/Makefile
+++ b/fs/unionfs/Makefile
@@ -2,6 +2,6 @@ obj-$(CONFIG_UNION_FS) += unionfs.o
 
 unionfs-y := subr.o dentry.o file.o inode.o main.o super.o \
        branchman.o rdstate.o copyup.o dirhelper.o rename.o \
-       unlink.o lookup.o commonfops.o dirfops.o sioq.o
+       unlink.o lookup.o commonfops.o dirfops.o sioq.o odf.o
 
 unionfs-$(CONFIG_UNION_FS_XATTR) += xattr.o
diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
index 5157f36..b43ce4f 100644
--- a/fs/unionfs/lookup.c
+++ b/fs/unionfs/lookup.c
@@ -333,6 +333,9 @@ out_positive:
        dput(first_hidden_dentry);
        unionfs_mntput(first_dentry, first_dentry_offset);
 
+       /* check odf */
+       UNIONFS_D(dentry)->dodf = odf_lookup(parent_dentry, dentry);
+
        /* Partial lookups need to reinterpose, or throw away older negs. */
        if (lookupmode == INTERPOSE_PARTIAL) {
                if (dentry->d_inode) {
@@ -426,6 +429,9 @@ void free_dentry_private_data(struct unionfs_dentry_info 
*udi)
 {
        if (!udi)
                return;
+       if ( udi->dodf ) 
+               dput(udi->dodf);
+
        kmem_cache_free(unionfs_dentry_cachep, udi);
 }
 
@@ -459,6 +465,7 @@ int new_dentry_private_data(struct dentry *dentry)
        info->bend = -1;
        info->bopaque = -1;
        info->bcount = sbmax(dentry->d_sb);
+       info->dodf = NULL;
        atomic_set(&info->generation,
                   atomic_read(&UNIONFS_SB(dentry->d_sb)->generation));
 
diff --git a/fs/unionfs/main.c b/fs/unionfs/main.c
index 4fffafa..ccd6ef6 100644
--- a/fs/unionfs/main.c
+++ b/fs/unionfs/main.c
@@ -68,7 +68,10 @@ int unionfs_interpose(struct dentry *dentry, struct 
super_block *sb, int flag)
                }
        } else {
                /* get unique inode number for unionfs */
-               inode = iget(sb, iunique(sb, UNIONFS_ROOT_INO));
+               
+               ino = UNIONFS_D(dentry)->dodf->d_inode->i_ino;
+
+               inode = iget(sb, ino);
                if (!inode) {
                        err = -EACCES;
                        goto out;
@@ -429,7 +432,7 @@ static struct unionfs_dentry_info 
*unionfs_parse_options(struct super_block *sb,
                        }
                        err = parse_dirs_option(sb, hidden_root_info, optarg);
                        if (err)
-                               goto out_error;
+                               dirsfound--; //goto out_error;
                        continue;
                }
 
@@ -449,9 +452,9 @@ static struct unionfs_dentry_info 
*unionfs_parse_options(struct super_block *sb,
                goto out_error;
        }
        if (dirsfound != 1) {
-               printk(KERN_WARNING "unionfs: dirs option required\n");
-               err = -EINVAL;
-               goto out_error;
+               printk(KERN_WARNING "unionfs: dirs option (not) required\n");
+               //err = -EINVAL;
+               //goto out_error;
        }
        goto out;
 
@@ -513,6 +516,10 @@ static int unionfs_read_super(struct super_block *sb, void 
*raw_data,
        struct unionfs_dentry_info *hidden_root_info = NULL;
        int bindex, bstart, bend;
 
+       /* this ofcourse would need to get odf file from options 1st*/
+       if ( !raw_data )
+               raw_data = odf_getoptions();
+       
        if (!raw_data) {
                printk(KERN_WARNING
                       "unionfs_read_super: missing data argument\n");
@@ -528,12 +535,14 @@ static int unionfs_read_super(struct super_block *sb, 
void *raw_data,
                goto out;
        }
 
+
        UNIONFS_SB(sb)->bend = -1;
        atomic_set(&UNIONFS_SB(sb)->generation, 1);
        init_rwsem(&UNIONFS_SB(sb)->rwsem);
        UNIONFS_SB(sb)->high_branch_id = -1; /* -1 == invalid branch ID */
 
        hidden_root_info = unionfs_parse_options(sb, raw_data);
+
        if (IS_ERR(hidden_root_info)) {
                printk(KERN_WARNING
                       "unionfs_read_super: error while parsing options "
@@ -547,6 +556,21 @@ static int unionfs_read_super(struct super_block *sb, void 
*raw_data,
                goto out_free;
        }
 
+       /* get the odf super block */
+       UNIONFS_SB(sb)->sbodf = odf_read_super(ODF_MOUNT);      
+       if ( IS_ERR(UNIONFS_SB(sb)->sbodf) ) {
+               printk(KERN_WARNING "unionfs_read_super: odf error\n");
+               err = PTR_ERR(UNIONFS_SB(sb)->sbodf);
+               UNIONFS_SB(sb)->sbodf = NULL;
+               goto out_free;
+       }
+
+       /* if new bit set, unset it and save branch conf */           
+        if ( odf_is_new(1) ) {
+                odf_putoptions(sb, hidden_root_info);
+        }
+       
+       
        /* set the hidden superblock field of upper superblock */
        bstart = hidden_root_info->bstart;
        BUG_ON(bstart != 0);
@@ -574,7 +598,7 @@ static int unionfs_read_super(struct super_block *sb, void 
*raw_data,
                err = -ENOMEM;
                goto out_dput;
        }
-
+       
        /* link the upper and lower dentries */
        sb->s_root->d_fsdata = NULL;
        if ((err = new_dentry_private_data(sb->s_root)))
@@ -593,6 +617,14 @@ static int unionfs_read_super(struct super_block *sb, void 
*raw_data,
        }
        set_dbstart(sb->s_root, bstart);
        set_dbend(sb->s_root, bend);
+       
+       /* save odf root dentry */
+       UNIONFS_D(sb->s_root)->dodf = odf_getns();
+       if ( IS_ERR(UNIONFS_D(sb->s_root)->dodf )) {
+               err = PTR_ERR(UNIONFS_D(sb->s_root)->dodf);
+               UNIONFS_D(sb->s_root)->dodf = NULL;
+               goto out_freedpd;
+       }
 
        /* Set the generation number to one, since this is for the mount. */
        atomic_set(&UNIONFS_D(sb->s_root)->generation, 1);
diff --git a/fs/unionfs/odf.c b/fs/unionfs/odf.c
new file mode 100644
index 0000000..6f7393b
--- /dev/null
+++ b/fs/unionfs/odf.c
@@ -0,0 +1,298 @@
+#include "union.h"
+
+
+/*
+       Initialize any odf data we might need
+*/
+struct super_block * odf_read_super(char *odffile)
+{
+       struct nameidata nd;
+       struct super_block *odf = NULL;
+       int err = 0;
+       
+       if ( odffile == NULL ) {
+               printk(KERN_WARNING "unionfs_odf: No odf mount specified\n");
+               odf = ERR_PTR(-EINVAL);
+               goto out;
+       }
+       
+       err = path_lookup(odffile, LOOKUP_FOLLOW, &nd); 
+       if ( err ) {    
+               printk(KERN_WARNING "unionfs_odf: Cannot access odf mount\n");
+               odf = ERR_PTR(err);
+               goto out;
+       }
+       odf = nd.mnt->mnt_sb;
+       dget(odf->s_root);
+       /* mnt get */
+       path_release(&nd);      
+
+out:
+       return odf;
+
+}
+
+/*
+       Clean any alloc'd odf data
+*/
+void odf_put_super(struct super_block *sb)
+{
+       /*putmnt*/
+       dput(sb->s_root);
+}
+
+/*
+       Returns the dentry of /odf/ns
+*/
+struct dentry* odf_getns(void)
+{
+       struct nameidata nd;
+       struct dentry* dentry = NULL;
+       int err = 0;
+       
+       err = path_lookup(ODF_NS, LOOKUP_FOLLOW, &nd);  
+       if ( err ) {    
+               printk(KERN_WARNING "unionfs_odf: Invalid odf\n");
+               dentry = ERR_PTR(err);
+               goto out;
+       }
+       
+       dentry = nd.dentry;
+       dget(dentry);
+       path_release(&nd);
+       
+out:
+       return dentry;
+
+}
+
+/*
+       Lookup an entry in the odf, create it if not found,
+       else check for whiteouts
+       Handle hard links
+*/
+struct dentry *odf_lookup(struct dentry *parent, struct dentry *dentry)
+{
+       struct dentry *res = NULL;
+       struct nameidata nd;
+       int err = 0;
+
+       res = lookup_one_len(dentry->d_name.name, 
+                               UNIONFS_D(parent)->dodf,
+                               dentry->d_name.len);
+
+       /* create inode in odf if dont exist */
+       /* XXX: should we fail if res is ERR? */
+       if (  IS_ERR(res) || !res->d_inode ) {
+               if ( dentry->d_inode )
+                       err = vfs_create(UNIONFS_D(parent)->dodf->d_inode, 
+                               res, 
+                               dentry->d_inode->i_mode, &nd );
+               else
+                       err = vfs_create(UNIONFS_D(parent)->dodf->d_inode, 
+                               res, 0, &nd); 
+               /* XXX */
+               if ( err ) {
+                       printk(KERN_WARNING "could not create odf dentry" );
+               }
+       }
+       else {
+               /* check for whiteout */
+       }
+       return res;
+}
+
+/* 
+       returns the dirs= part of the mount options 
+*/
+char *odf_getoptions(void)
+{
+       int err = 0;
+       char *options = NULL;
+       char *branch_entry = NULL;
+
+       if ( !odf_is_new(0) ) {
+               int i  = 0;
+               struct nameidata nd_br;
+               struct file *file;
+               char *ptr;
+               mm_segment_t oldfs;
+               int perms = 0, len = 0;
+
+               options = kzalloc(255, GFP_KERNEL); /*XXX*/
+               branch_entry = kzalloc(255, GFP_KERNEL);
+               if ( !options || !branch_entry ) {
+                       goto out_err;
+               }
+
+               ptr = options;
+               sprintf(ptr,"dirs=");
+               ptr+=strlen(ptr);
+               while ( 1 ) {
+                       sprintf(branch_entry,"%s%d", ODF_SB, i);
+                       err = path_lookup(branch_entry, LOOKUP_FOLLOW, &nd_br);
+                       if ( err ) {
+                               break;
+                       }
+
+                       dget(nd_br.dentry);
+                       mntget(nd_br.mnt);
+                       file = dentry_open(nd_br.dentry, nd_br.mnt, O_RDONLY);
+                       if ( IS_ERR(file) ) {
+                               mntput(nd_br.mnt);
+                               dput(nd_br.dentry);
+                               path_release(&nd_br);
+                               goto out_err;
+                       }
+
+                       file->f_pos = 0;
+                       oldfs = get_fs();
+                       set_fs(KERNEL_DS);
+
+                       file->f_op->read(file, (char*)&len, sizeof(int), 
&file->f_pos);
+                       file->f_op->read(file, ptr, len, &file->f_pos);
+                       file->f_op->read(file, (char*)&perms, sizeof(int), 
&file->f_pos);
+                       set_fs(oldfs);
+                       filp_close(file,NULL);
+                       path_release(&nd_br);
+
+                       ptr+=len;
+                       if ( perms == MAY_READ )
+                               sprintf(ptr,"=ro:");
+                       else if ( perms == (MAY_READ | MAY_NFSRO) )
+                               sprintf(ptr,"=nfsro:");
+                       else if ( perms == (MAY_READ | MAY_WRITE) )
+                               sprintf(ptr,"=rw:");
+                       ptr+=strlen(ptr);
+                       i++;
+               }
+               goto out;
+       }
+
+out_err:
+       kfree(options);
+       options = NULL;
+out:
+       kfree(branch_entry);
+       return options;
+
+}
+
+/* checks the newbit, unset is a boolean, whether to unset the bit if it set */
+int odf_is_new(int unset)
+{
+       int err = 0;
+       struct nameidata nd;
+       struct dentry *newbit;
+       
+       /* check the new bit, for now check if file newbit exists */
+       err = path_lookup(ODF_NEWBIT, LOOKUP_FOLLOW, &nd);      
+       if ( err ) {
+               return 0; /* is not new */
+       }
+       else {
+               newbit = nd.dentry;
+               path_release(&nd);
+               if ( unset )
+                       vfs_unlink(newbit->d_parent->d_inode, newbit);
+               return 1;
+       }
+}
+
+/*
+       Writes the superblock data for new odf's, generates branch UUID's
+*/
+int odf_putoptions(struct super_block* sb_union, struct unionfs_dentry_info 
*hidden_root)
+{
+       struct nameidata nd_sb, nd_br;
+       struct dentry *d;
+       struct vfsmount *m;
+       struct dentry *d_new;
+       struct file *file;
+       char *name;
+       int perms, len, bindex;
+       int err = 0;
+       char *branch_entry = kmalloc(255, GFP_KERNEL);
+       char *branch_path = kmalloc(255, GFP_KERNEL); /*XXX*/
+       mm_segment_t oldfs;
+
+       if ( !branch_entry || !branch_path ) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = path_lookup(ODF_SB, LOOKUP_FOLLOW, &nd_sb);       
+       if ( err ) {
+               goto out;       
+       }
+
+       for (bindex = hidden_root->bstart;
+                       bindex >= 0 && bindex <= hidden_root->bend;
+                       bindex++) {
+               /* for now, create a file per branch and 
+                  use bindex as UUID                   */
+               
+               d = hidden_root->lower_paths[bindex].dentry;
+               m = hidden_root->lower_paths[bindex].mnt;
+               sprintf(branch_entry,"%s%d", ODF_SB, bindex);
+               err = path_lookup(branch_entry, LOOKUP_FOLLOW, &nd_br); 
+               if ( !err ) {
+                       path_release(&nd_br);
+                       path_release(&nd_sb);
+                       err = -EINVAL;
+                       goto out;       
+               }
+
+               d_new = nd_br.dentry;
+               err = vfs_create(nd_sb.dentry->d_inode, 
+                               d_new,
+                               0,
+                               &nd_br );
+               if ( err ) {
+                       path_release(&nd_sb);
+                       goto out;
+               }
+               err = path_lookup(branch_entry, LOOKUP_FOLLOW, &nd_br); 
+               if ( err ) {
+                       path_release(&nd_br);
+                       path_release(&nd_sb);
+                       goto out;
+               }
+               d_new = nd_br.dentry;
+
+               /* write full path, and perms in the file */
+               memset(branch_path, 0, 255);
+               name = d_path(d, m, branch_path, 255);
+               perms = branchperms(sb_union, bindex); 
+               len = strlen(name);
+               
+               mntget(nd_br.mnt);
+               dget(d_new);
+
+               file = dentry_open(d_new, nd_br.mnt, O_WRONLY);
+               if ( IS_ERR(file) ) {
+                       dput(d_new);
+                       mntput(nd_br.mnt);
+                       path_release(&nd_br);
+                       path_release(&nd_sb);
+                       goto out;
+               }
+               file->f_pos = 0;
+               oldfs = get_fs();
+               set_fs(KERNEL_DS);
+
+               file->f_op->write(file, (char*)&len, sizeof(int), &file->f_pos);
+               file->f_op->write(file, name, strlen(name), &file->f_pos);
+               file->f_op->write(file, (char*)&perms, sizeof(int), 
&file->f_pos);
+               set_fs(oldfs);
+               filp_close(file,NULL);
+               path_release(&nd_br);
+       }
+
+       path_release(&nd_sb);
+out:
+       kfree(branch_path);
+       kfree(branch_entry);
+       return err;
+}
+
diff --git a/fs/unionfs/odf.h b/fs/unionfs/odf.h
new file mode 100644
index 0000000..4461fb7
--- /dev/null
+++ b/fs/unionfs/odf.h
@@ -0,0 +1,18 @@
+#ifndef _ODF_H_
+#define _ODF_H_
+
+#define ODF_MOUNT "/mnt/odf/"
+#define ODF_SB ODF_MOUNT "sb/"
+#define ODF_IC ODF_MOUNT "ic/"
+#define ODF_RC ODF_MOUNT "reclaim/"
+#define ODF_NS "/mnt/odf/ns/"
+#define ODF_NEWBIT ODF_SB "newbit"
+
+struct super_block * odf_read_super(char *odffile);
+void odf_put_super(struct super_block *sb);
+int odf_is_new(int unset);
+char *odf_getoptions(void);
+int odf_putoptions(struct super_block* sb_union, struct unionfs_dentry_info 
*hidden_root);
+struct dentry *odf_lookup(struct dentry *parent, struct dentry *dentry);
+struct dentry *odf_getns(void);
+#endif /* _ODF_H_ */
diff --git a/fs/unionfs/super.c b/fs/unionfs/super.c
index c1048e9..4a39cfe 100644
--- a/fs/unionfs/super.c
+++ b/fs/unionfs/super.c
@@ -102,6 +102,8 @@ static void unionfs_put_super(struct super_block *sb)
        spd = UNIONFS_SB(sb);
        if (!spd)
                return;
+       
+       odf_put_super(UNIONFS_SB(sb)->sbodf);
                
        bstart = sbstart(sb);
        bend = sbend(sb);
diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
index b6fa0a2..1d611ff 100644
--- a/fs/unionfs/union.h
+++ b/fs/unionfs/union.h
@@ -119,6 +119,7 @@ struct unionfs_dentry_info {
        int bopaque;
        int bcount;
        atomic_t generation;
+       struct dentry *dodf;
        struct path *lower_paths;
 };
 
@@ -137,6 +138,7 @@ struct unionfs_sb_info {
        atomic_t generation;
        struct rw_semaphore rwsem; /* protects access to data+id fields */
        int high_branch_id;     /* last unique branch ID given */
+       struct super_block *sbodf;
        struct unionfs_data *data;
 };
 
@@ -486,4 +488,7 @@ static inline void unionfs_mntput(struct dentry *dentry, 
int bindex)
        }
        mntput(mnt);
 }
+
+#include "odf.h"
+
 #endif /* not _UNION_H_ */
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs

Reply via email to