commit 35d03efeb9e6508de1542c4a9f89efeb092252bb
Author: Yiannis Pericleous <[EMAIL PROTECTED]>
Date:   Sun Mar 25 17:29:11 2007 -0400

    update odf sb data on remounts

diff --git a/fs/unionfs/main.c b/fs/unionfs/main.c
index c200f3a..46a088d 100644
--- a/fs/unionfs/main.c
+++ b/fs/unionfs/main.c
@@ -538,6 +538,7 @@ static int unionfs_read_super(struct super_block *sb, void 
*raw_data,
        struct unionfs_dentry_info *hidden_root_info = NULL;
        int bindex, bstart, bend;
        char *odf_options = NULL;
+       int *bid = NULL, high_bid;
        int put_ns = 0; /* we dget the ns dentry in odf_read_super but do not
                         * put it in odf_put_super since it is also assigned to 
s_root
                         * and will be put by s_root. put_ns decides if we got
@@ -563,7 +564,10 @@ static int unionfs_read_super(struct super_block *sb, void 
*raw_data,
        init_rwsem(&UNIONFS_SB(sb)->rwsem);
        UNIONFS_SB(sb)->high_branch_id = -1; /* -1 == invalid branch ID */
 
-       /* get the odf super block */
+       /* get the odf super block
+        * Try to extract the odf option from the mount time options and
+        * then initialize odf sb data
+        */
        UNIONFS_SB(sb)->odf = odf_read_super(raw_data);
        if (IS_ERR(UNIONFS_SB(sb)->odf)) {
                printk(KERN_WARNING "unionfs_read_super: odf error\n");
@@ -572,11 +576,15 @@ static int unionfs_read_super(struct super_block *sb, 
void *raw_data,
                goto out_free;
        }
        put_ns = 1;
+
+       /* if this is an old odf reconstruct the dirs part of the mount time 
options
+        * from the odf data on disk and discard the old options
+        */
        if (!odf_is_new(UNIONFS_SB(sb)->odf)) {
-               odf_options = odf_get_options(UNIONFS_SB(sb)->odf);
-               if (!odf_options) {
+               odf_options = odf_read_sb_data(UNIONFS_SB(sb)->odf, &bid);
+               if (IS_ERR(odf_options)) {
                        printk(KERN_WARNING "unionfs_read_super: could not load 
options from odf\n");
-                       err = -EINVAL;
+                       err = PTR_ERR(odf_options);
                        goto out_free;
                }
                if (strstr(raw_data,"dirs="))
@@ -600,7 +608,11 @@ static int unionfs_read_super(struct super_block *sb, void 
*raw_data,
 
        /* if new bit set, unset it and save branch conf */           
        if (odf_is_new(UNIONFS_SB(sb)->odf)) {
-               err = odf_put_options(sb, hidden_root_info);
+               err = odf_write_sb_data(
+                               UNIONFS_SB(sb)->odf,
+                               UNIONFS_SB(sb)->data,
+                               hidden_root_info->lower_paths,
+                               hidden_root_info->bend - 
hidden_root_info->bstart + 1);
                if (err)
                        goto out_free;
                /* here we can safely mark the odf as not new */
@@ -611,6 +623,7 @@ static int unionfs_read_super(struct super_block *sb, void 
*raw_data,
        bstart = hidden_root_info->bstart;
        BUG_ON(bstart != 0);
        sbend(sb) = bend = hidden_root_info->bend;
+       high_bid = -1;
        for (bindex = bstart; bindex <= bend; bindex++) {
                struct dentry *d;
 
@@ -619,7 +632,18 @@ static int unionfs_read_super(struct super_block *sb, void 
*raw_data,
                unionfs_write_lock(sb);
                unionfs_set_lower_super_idx(sb, bindex, d->d_sb);
                unionfs_write_unlock(sb);
+
+               if (bid) {
+                       /* we need to update the branch ids to whatever was 
stored in
+                        * the odf and set high_branch_id to the greatest
+                        */
+                       UNIONFS_SB(sb)->data[bindex].branch_id = bid[bindex];
+                       if (bid[bindex] > high_bid)
+                               high_bid = bid[bindex];
+               }
        }
+       if (high_bid > UNIONFS_SB(sb)->high_branch_id)
+                UNIONFS_SB(sb)->high_branch_id = high_bid;
 
        /* Unionfs: Max Bytes is the maximum bytes from highest priority branch 
*/
        unionfs_read_lock(sb);
@@ -706,6 +730,7 @@ out_free:
        sb->s_fs_info = NULL;
 
 out:
+       kfree(bid);
        kfree(odf_options);
        if (hidden_root_info && !IS_ERR(hidden_root_info)) {
                kfree(hidden_root_info->lower_paths);
diff --git a/fs/unionfs/odf.c b/fs/unionfs/odf.c
index f11af8f..9d9d6ce 100644
--- a/fs/unionfs/odf.c
+++ b/fs/unionfs/odf.c
@@ -913,99 +913,6 @@ int __odf_set_opaque(struct inode *i, int branch)
 }
 
 /* 
- * Requires an odf_sb_info, returns the dirs= part of the mount options 
- */
-char *odf_get_options(struct odf_sb_info *odf_sb)
-{
-       int err = 0;
-       char *options = NULL;
-       char *branch_entry = NULL;
-       struct dentry *d_content;
-       struct file *file;
-       char *ptr;
-       mm_segment_t oldfs;
-       int perms, len, count, version;
-       unsigned char uuid[UUID_LEN];
-       __le32 le32;
-
-       options = kzalloc(ODF_OPTIONS_LEN, GFP_KERNEL); /*XXX*/
-       branch_entry = kzalloc(ODF_BRANCH_PATH, GFP_KERNEL);
-       if (!options || !branch_entry) {
-               err = -ENOMEM;
-               goto out_err;
-       }
-
-       ptr = options;
-       sprintf(ptr,"dirs=");
-       ptr+=strlen(ptr);
-
-       d_content = lookup_one_len(ODF_CONTENT, odf_sb->odi_sb->dentry, 
ODF_CONTENT_LEN);
-       if (IS_ERR(d_content) || !d_content) {
-               err = -EINVAL;
-               goto out_err;
-       }
-       else if (!d_content->d_inode) {
-               dput(d_content);
-               err = -EINVAL;
-               goto out_err;
-       }
-       
-       mntget(odf_sb->mnt);
-       file = dentry_open(d_content, odf_sb->mnt, O_RDONLY);
-       if (IS_ERR(file)) {
-               mntput(odf_sb->mnt);
-               dput(d_content);
-               goto out_err;
-       }
-
-       file->f_pos = 0;
-       oldfs = get_fs();
-       set_fs(KERNEL_DS);
-
-       /* version */
-       file->f_op->read(file, (char*)&le32, sizeof(__le32), &file->f_pos);
-       /* check version - dont allow greater than current */
-       version = le32_to_cpu(le32);
-       if (((version >> 16) > ODF_VERSION_MAJOR) ||
-               (((version >> 16) == ODF_VERSION_MAJOR) &&
-                (version & 0x0000FFFF) > ODF_VERSION_MINOR)) {
-               printk(KERN_WARNING "unionfs: unsupported odf version\n");
-               goto out_close;
-       }
-
-       /* branch count */
-       file->f_op->read(file, (char*)&le32, sizeof(__le32), &file->f_pos);
-       count = le32_to_cpu(le32);
-       while (count) {
-               file->f_op->read(file, (char*)&le32, sizeof(__le32), 
&file->f_pos);
-               len = le32_to_cpu(le32);
-               file->f_op->read(file, ptr, len, &file->f_pos);
-               file->f_op->read(file, (char*)&le32, sizeof(__le32), 
&file->f_pos);
-               perms = le32_to_cpu(le32);
-               file->f_op->read(file, (char*)uuid, UUID_LEN, &file->f_pos);
-               ptr+=len;
-               if (perms == MAY_READ)
-                       sprintf(ptr,"=ro:");
-               else if (perms == (MAY_READ | MAY_WRITE))
-                       sprintf(ptr,"=rw:");
-               ptr+=strlen(ptr);
-               count--;
-       }
-       set_fs(oldfs);
-       filp_close(file,NULL);
-       goto out;
-out_close:
-       set_fs(oldfs);
-       filp_close(file,NULL);
-out_err:
-       kfree(options);
-       options = NULL;
-out:
-       kfree(branch_entry);
-       return options;
-}
-
-/* 
  * checks the newbit 
  */
 int odf_is_new(struct odf_sb_info *osi)
@@ -1045,37 +952,41 @@ void odf_unset_newbit(struct odf_sb_info *osi)
 }
 
 /*
- *     Writes the superblock data for new odf's, generates branch UUID's
+ * Writes the superblock data for new odf's, generates branch UUID's
+ * Superblock contains:
+ *     odf version number, numbers of branches
+ *     then for each branch:
+ *             branch id, ablosute path len, absolute path, perms, uuids
  */
-int odf_put_options(struct super_block* sb_union, struct unionfs_dentry_info 
*hidden_root)
+int odf_write_sb_data(struct odf_sb_info* osi, struct unionfs_data *data, 
struct path *lower_paths, int branches)
 {
        struct dentry *d, *d_odf_sb, *d_content;
        struct vfsmount *m, *odf_mnt;
        struct file *file;
        char *name;
-       int perms, len, bindex, i;
-       int count, err = 0;
+       int count, len, bindex, i;
+       int err = 0;
        __le32 le32;
        unsigned char *uuid = NULL;
-       u32 *bid = NULL;
+       u32 *buuid = NULL;
        char *branch_entry = kmalloc(ODF_BRANCH_PATH, GFP_KERNEL);
        char *branch_path = kmalloc(ODF_BRANCH_PATH, GFP_KERNEL);
        mm_segment_t oldfs;
+       struct iattr attr;
 
        if (!branch_entry || !branch_path) {
                err = -ENOMEM;
                goto out;
        }
 
-       d_odf_sb = UNIONFS_SB(sb_union)->odf->odi_sb->dentry;
-       odf_mnt = UNIONFS_SB(sb_union)->odf->mnt;
+       d_odf_sb = osi->odi_sb->dentry;
+       odf_mnt = osi->mnt;
 
        /* check the number of branches */
-       count = hidden_root->bend - hidden_root->bstart + 1;
-       if (count >= (1 << ODF_OPQ_BITS)) {
+       if (branches >= (1 << ODF_OPQ_BITS)) {
                printk(KERN_WARNING "unionfs: too many branches (%d), "
                        "odf can only support %d branches\n",
-                       count, (1 << ODF_OPQ_BITS) - 1);
+                       branches, (1 << ODF_OPQ_BITS) - 1);
                err = -EINVAL;
                goto out;
        }
@@ -1086,13 +997,20 @@ int odf_put_options(struct super_block* sb_union, struct 
unionfs_dentry_info *hi
                goto out;
        }
        else if (d_content->d_inode) {
-               err = -EINVAL;
-               dput(d_content);
-               goto out;
+               /* truncate */
+               attr.ia_size = 0;
+               attr.ia_valid = ATTR_SIZE | ATTR_FORCE;
+               err = notify_change(d_content, &attr);
+               if (err) {
+                       dput(d_content);
+                       goto out;
+               }
+       }
+       else {
+               err = vfs_create(d_odf_sb->d_inode, d_content, 0, NULL );
+               if (err)
+                       goto out;
        }
-       err = vfs_create(d_odf_sb->d_inode, d_content, 0, NULL );
-       if (err)
-               goto out;
 
        mntget(odf_mnt);
 
@@ -1113,47 +1031,47 @@ int odf_put_options(struct super_block* sb_union, 
struct unionfs_dentry_info *hi
        file->f_op->write(file, (char*)&le32, sizeof(__le32), &file->f_pos);
 
        /* number of branches */
-       le32 = cpu_to_le32(count);
+       le32 = cpu_to_le32(branches);
        file->f_op->write(file, (char*)&le32, sizeof(__le32), &file->f_pos);
 
-       bid = kmalloc(count * sizeof(u32), GFP_KERNEL);
-       uuid = kmalloc(count * UUID_LEN, GFP_KERNEL);
-       if (!bid || !uuid) {
+       buuid = kmalloc(branches * sizeof(u32), GFP_KERNEL);
+       uuid = kmalloc(branches * UUID_LEN, GFP_KERNEL);
+       if (!buuid || !uuid) {
                err = -ENOMEM;
                goto out_close;
        }
        count = 0;
 
        /* now info about each branch */
-       for (bindex = hidden_root->bstart;
-                       bindex >= 0 && bindex <= hidden_root->bend;
-                       bindex++) {
+       for (bindex = 0; bindex < branches; bindex++) {
 
-               d = hidden_root->lower_paths[bindex].dentry;
-               m = hidden_root->lower_paths[bindex].mnt;
+               d = lower_paths[bindex].dentry;
+               m = lower_paths[bindex].mnt;
 
-               /* write full path, and perms in the file */
+               /* write bid, full path, perms and uuids in the file */
                memset(branch_path, 0, ODF_BRANCH_PATH);
                name = d_path(d, m, branch_path, ODF_BRANCH_PATH);
-               perms = branchperms(sb_union, bindex); 
                len = strlen(name);
        
                /* generate UUIDs, we want to have same ids for same fss*/
+               /* XXX: Right now we lose previous UUIDs on remounts */
                for (i = 0; i < count; i++) {
-                       if ((u32)m == bid[i])
+                       if ((u32)m == buuid[i])
                                break;
                }
                if (i == count)
                        generate_random_uuid(uuid + count * UUID_LEN);
                else
                        memcpy(uuid + count * UUID_LEN, uuid + i * UUID_LEN, 
UUID_LEN);
-               bid[count] = (u32)m;
+               buuid[count] = (u32)m;
 
                /* write */
+               le32 = cpu_to_le32(data[bindex].branch_id);
+               file->f_op->write(file, (char*)&le32, sizeof(__le32), 
&file->f_pos);
                le32 = cpu_to_le32(len);        
                file->f_op->write(file, (char*)&le32, sizeof(__le32), 
&file->f_pos);
                file->f_op->write(file, name, strlen(name), &file->f_pos);
-               le32 = cpu_to_le32(perms);
+               le32 = cpu_to_le32(data[bindex].branchperms);
                file->f_op->write(file, (char*)&le32, sizeof(__le32), 
&file->f_pos);
                file->f_op->write(file, (char*)uuid + count * UUID_LEN, 
UUID_LEN, &file->f_pos);
                count++;
@@ -1164,13 +1082,121 @@ out_close:
        filp_close(file,NULL);
 out:
        kfree(uuid);
-       kfree(bid);
+       kfree(buuid);
        kfree(branch_path);
        kfree(branch_entry);
        return err;
 }
 
 /* 
+ * Reads the odf sb data and returns the dirs= part of the mount options
+ * and the bids for each branch
+ */
+char *odf_read_sb_data(struct odf_sb_info *odf_sb, int **bid)
+{
+       int err = 0;
+       char *options = NULL;
+       char *branch_entry = NULL;
+       struct dentry *d_content;
+       struct file *file;
+       char *ptr;
+       mm_segment_t oldfs;
+       int perms, len, count, i, version;
+       unsigned char uuid[UUID_LEN];
+       __le32 le32;
+
+       options = kzalloc(ODF_OPTIONS_LEN, GFP_KERNEL); /*XXX*/
+       branch_entry = kzalloc(ODF_BRANCH_PATH, GFP_KERNEL);
+       if (!options || !branch_entry) {
+               err = -ENOMEM;
+               goto out_err;
+       }
+
+       ptr = options;
+       sprintf(ptr,"dirs=");
+       ptr+=strlen(ptr);
+
+       d_content = lookup_one_len(ODF_CONTENT, odf_sb->odi_sb->dentry, 
ODF_CONTENT_LEN);
+       if (IS_ERR(d_content) || !d_content) {
+               err = -EINVAL;
+               goto out_err;
+       }
+       else if (!d_content->d_inode) {
+               dput(d_content);
+               err = -EINVAL;
+               goto out_err;
+       }
+       
+       mntget(odf_sb->mnt);
+       file = dentry_open(d_content, odf_sb->mnt, O_RDONLY);
+       if (IS_ERR(file)) {
+               mntput(odf_sb->mnt);
+               dput(d_content);
+               goto out_err;
+       }
+
+       file->f_pos = 0;
+       oldfs = get_fs();
+       set_fs(KERNEL_DS);
+
+       /* version */
+       file->f_op->read(file, (char*)&le32, sizeof(__le32), &file->f_pos);
+       /* check version - dont allow greater than current */
+       version = le32_to_cpu(le32);
+       if (((version >> 16) > ODF_VERSION_MAJOR) ||
+               (((version >> 16) == ODF_VERSION_MAJOR) &&
+                (version & 0x0000FFFF) > ODF_VERSION_MINOR)) {
+               printk(KERN_WARNING "unionfs: unsupported odf version\n");
+               goto out_close;
+       }
+
+       /* branch count */
+       file->f_op->read(file, (char*)&le32, sizeof(__le32), &file->f_pos);
+       count = le32_to_cpu(le32);
+       
+       if (count <= 0) {
+               printk(KERN_WARNING "unionfs: odf branch count = %d\n", count);
+               goto out_close;
+       }
+
+       *bid = kmalloc(count * sizeof(int), GFP_KERNEL);
+       if (!(*bid)) {
+               err = -ENOMEM;
+               goto out_close;
+       }
+
+       i = 0;
+       while (i < count) {
+               file->f_op->read(file, (char*)&le32, sizeof(__le32), 
&file->f_pos);
+               (*bid)[i] = le32_to_cpu(le32);
+               file->f_op->read(file, (char*)&le32, sizeof(__le32), 
&file->f_pos);
+               len = le32_to_cpu(le32);
+               file->f_op->read(file, ptr, len, &file->f_pos);
+               file->f_op->read(file, (char*)&le32, sizeof(__le32), 
&file->f_pos);
+               perms = le32_to_cpu(le32);
+               file->f_op->read(file, (char*)uuid, UUID_LEN, &file->f_pos);
+               ptr+=len;
+               if (perms == MAY_READ)
+                       sprintf(ptr,"=ro:");
+               else if (perms == (MAY_READ | MAY_WRITE))
+                       sprintf(ptr,"=rw:");
+               ptr+=strlen(ptr);
+               i++;
+       }
+       set_fs(oldfs);
+       filp_close(file,NULL);
+       goto out;
+out_close:
+       set_fs(oldfs);
+       filp_close(file,NULL);
+out_err:
+       kfree(options);
+       options = ERR_PTR(err);
+out:
+       kfree(branch_entry);
+       return options;
+}
+/* 
  * Allocates an odi and fills it with inode and dentry 
  */
 struct odf_dentry_info *odf_alloc_info(struct odf_sb_info *osi, struct dentry 
*odf_dentry)
@@ -1229,15 +1255,14 @@ void __odf_cleanup(void *args)
        vfs_statfs(cl->odf->odi_sb->dentry, &stat);
        if (stat.f_bavail * 100 < stat.f_blocks * ODF_CL_PCNT_B) {
                cleanup = 1;
-               printk("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_ffree * ODF_CL_PCNT_I) {
                cleanup = 1;
-               printk("cleanup thread: free inodes below critical size\n");
+               printk("unionfs cleanup thread: free inodes below critical 
size\n");
        }
        if (cleanup)
                err = unionfs_force_rmdir(cl->odf->mnt, odi_ic->dentry, 
FRMV_NOTPARENT|FRMV_LEAF);
-       BUG_ON(err); /* temporary */
 
        odf_unlock(odi_ic);
        
diff --git a/fs/unionfs/odf.h b/fs/unionfs/odf.h
index 6a2d1fa..fee8a1a 100644
--- a/fs/unionfs/odf.h
+++ b/fs/unionfs/odf.h
@@ -53,8 +53,8 @@ struct odf_sb_info* odf_read_super(char *options);
 void odf_put_super(struct odf_sb_info *osi);
 int odf_is_new(struct odf_sb_info *osi);
 void odf_unset_newbit(struct odf_sb_info *osi);
-char *odf_get_options(struct odf_sb_info *odf_sb);
-int odf_put_options(struct super_block* sb_union, struct unionfs_dentry_info 
*hidden_root);
+char *odf_read_sb_data(struct odf_sb_info *odf_sb, int **bid);
+int odf_write_sb_data(struct odf_sb_info* osi, struct unionfs_data *data, 
struct path *lower_paths, int branches);
 int odf_parse_options(char *options, char **odf_path);
 int odf_is_odf(struct dentry *d_odf);
 
diff --git a/fs/unionfs/super.c b/fs/unionfs/super.c
index d5ec7ee..352a6db 100644
--- a/fs/unionfs/super.c
+++ b/fs/unionfs/super.c
@@ -674,6 +674,16 @@ out_no_change:
                new_lower_paths = tmp_lower_paths;
        }
 
+       /* now update the odf. rewrite the superblock data file with all
+        * the new branch information
+        */
+       err = odf_write_sb_data(UNIONFS_SB(sb)->odf,
+                       new_data,
+                       new_lower_paths,
+                       new_branches);
+       if (err)
+               goto out_release;
+
        /*
         * OK, just before we actually put the new set of branches in place,
         * we need to ensure that our own f/s has no dirty objects left.
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs

Reply via email to