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