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