commit ba36e26c681252e0fe11c3a0c4ed4d3fd2d6ad4f
Author: Yiannis Pericleous <[EMAIL PROTECTED]>
Date: Wed Apr 11 18:34:19 2007 -0400
on mount, expect an empty odf dir and create the hierarchy
diff --git a/fs/unionfs/dirhelper.c b/fs/unionfs/dirhelper.c
index b03a061..840e6e3 100644
--- a/fs/unionfs/dirhelper.c
+++ b/fs/unionfs/dirhelper.c
@@ -441,26 +441,16 @@ out_sb:
return err;
}
-/* Remove the hidden dentry by:
- * a) rmdir if its a physically empty dir
- * b) silly rename if its not physically empty
- * c) unlink if not a dir
+/* Checks if the given directory is physically empty
+ * Returns 0 if it is empty and -ENOTEMPTY if not
*/
-int unionfs_force_rm(struct dentry *dentry, struct dentry **hidden_dentry, int
bindex)
+int check_empty_lower(struct dentry *lower_dentry, struct vfsmount *mnt)
{
- struct file *hidden_file;
- struct super_block *sb;
+ struct file *lower_file;
struct unionfs_rdutil_callback *buf = NULL;
int err;
- sb = dentry->d_sb;
- if (!S_ISDIR((*hidden_dentry)->d_inode->i_mode)) {
- err = vfs_unlink((*hidden_dentry)->d_parent->d_inode,
- (*hidden_dentry));
- if (err)
- goto out;
- goto refresh;
- }
+ BUG_ON(!S_ISDIR(lower_dentry->d_inode->i_mode));
/* check if dir is empty */
buf = kmalloc(sizeof(struct unionfs_rdutil_callback), GFP_KERNEL);
@@ -474,29 +464,51 @@ int unionfs_force_rm(struct dentry *dentry, struct dentry
**hidden_dentry, int b
buf->dir = NULL;
buf->filp = NULL;
- dget(*hidden_dentry);
- mntget(unionfs_lower_mnt_idx(dentry, bindex));
- branchget(sb, bindex);
- hidden_file = dentry_open(*hidden_dentry,
- unionfs_lower_mnt_idx(dentry, bindex),
- O_RDONLY);
- if (IS_ERR(hidden_file)) {
- err = PTR_ERR(hidden_file);
- dput(*hidden_dentry);
- branchput(sb, bindex);
+ dget(lower_dentry);
+ mntget(mnt);
+ lower_file = dentry_open(lower_dentry, mnt, O_RDONLY);
+ if (IS_ERR(lower_file)) {
+ err = PTR_ERR(lower_file);
+ dput(lower_dentry);
+ mntput(mnt);
goto out;
}
do {
buf->filldir_called = 0;
- err = vfs_readdir(hidden_file,
- readdir_util_callback, buf);
- if (buf->err)
- err = buf->err;
+ err = vfs_readdir(lower_file, readdir_util_callback, buf);
+ if (buf->err)
+ err = buf->err;
} while ((err >= 0) && buf->filldir_called);
- /* fput calls dput for hidden_dentry */
- fput(hidden_file);
+ fput(lower_file);
+out:
+ kfree(buf);
+ return err;
+}
+
+/* Remove the hidden dentry by:
+ * a) rmdir if its a physically empty dir
+ * b) silly rename if its not physically empty
+ * c) unlink if not a dir
+ */
+int unionfs_force_rm(struct dentry *dentry, struct dentry **hidden_dentry, int
bindex)
+{
+ struct super_block *sb;
+ int err;
+
+ sb = dentry->d_sb;
+ if (!S_ISDIR((*hidden_dentry)->d_inode->i_mode)) {
+ err = vfs_unlink((*hidden_dentry)->d_parent->d_inode,
+ (*hidden_dentry));
+ if (err)
+ goto out;
+ goto refresh;
+ }
+
+ /* check if dir is empty */
+ branchget(sb, bindex);
+ err = check_empty_lower(*hidden_dentry, unionfs_lower_mnt_idx(dentry,
bindex));
branchput(sb, bindex);
if (err == 0)
@@ -524,8 +536,6 @@ refresh:
}
unionfs_set_lower_dentry_idx(dentry, bindex, *hidden_dentry);
out:
- if (buf)
- kfree(buf);
return err;
}
diff --git a/fs/unionfs/main.c b/fs/unionfs/main.c
index 63b5c0c..4a6f81a 100644
--- a/fs/unionfs/main.c
+++ b/fs/unionfs/main.c
@@ -611,7 +611,7 @@ static int unionfs_read_super(struct super_block *sb, void
*raw_data,
goto out_free;
}
- /* if new bit set, unset it and save branch conf */
+ /* if odf is new, save branch conf */
if (odf_is_new(odf)) {
/* generate new uuids */
@@ -626,8 +626,6 @@ static int unionfs_read_super(struct super_block *sb, void
*raw_data,
hidden_root_info->bend -
hidden_root_info->bstart + 1);
if (err)
goto out_free;
- /* here we can safely mark the odf as not new */
- odf_unset_newbit(odf);
}
/* set the hidden superblock field of upper superblock */
diff --git a/fs/unionfs/odf.c b/fs/unionfs/odf.c
index 812cd53..65a75f0 100644
--- a/fs/unionfs/odf.c
+++ b/fs/unionfs/odf.c
@@ -1,4 +1,85 @@
#include "union.h"
+
+/* Create a directory in odf
+ * Fails if the directory already exists
+ */
+static inline struct dentry * __odf_create_dir(struct dentry *parent, char
*name)
+{
+ struct dentry *dentry = NULL;
+ int err;
+
+ dentry = lookup_one_len(name, parent, strlen(name));
+ if (IS_ERR(dentry))
+ goto out;
+ if (unlikely(dentry->d_inode)) {
+ dput(dentry);
+ dentry = ERR_PTR(-EINVAL);
+ goto out;
+ }
+ err = vfs_mkdir(parent->d_inode, dentry, S_IRWXUGO);
+ if (err) {
+ dput(dentry);
+ dentry = ERR_PTR(err);
+ }
+out:
+ return dentry;
+}
+
+/* Creates the hierarchy for a fresh odf file.
+ * It fails if any of the dirs/files to be created existed before
+ */
+int __odf_create_hierarchy(struct dentry *odf_root)
+{
+ struct dentry *dentry = NULL, *dentry_wh = NULL;
+ int err = 0;
+
+ dentry = __odf_create_dir(odf_root, ODF_NS);
+ if (IS_ERR(dentry)){
+ err = PTR_ERR(dentry);
+ dentry = NULL;
+ goto out;
+ }
+ dput(dentry);
+ dentry = __odf_create_dir(odf_root, ODF_IC);
+ if (IS_ERR(dentry)){
+ err = PTR_ERR(dentry);
+ dentry = NULL;
+ goto out;
+ }
+ dput(dentry);
+ dentry = __odf_create_dir(odf_root, ODF_RC);
+ if (IS_ERR(dentry)){
+ err = PTR_ERR(dentry);
+ dentry = NULL;
+ goto out;
+ }
+ dput(dentry);
+ dentry = __odf_create_dir(odf_root, ODF_SB);
+ if (IS_ERR(dentry)){
+ err = PTR_ERR(dentry);
+ dentry = NULL;
+ goto out;
+ }
+ dentry_wh = lookup_one_len(ODF_WH_NAME, dentry, ODF_WH_LEN);
+ if (IS_ERR(dentry_wh)) {
+ err = PTR_ERR(dentry_wh);
+ dentry_wh = NULL;
+ goto out;
+ }
+ if (unlikely(dentry_wh->d_inode)){
+ err = -EINVAL;
+ goto out;
+ }
+ err = vfs_create(dentry->d_inode, dentry_wh, S_IRWXUGO, NULL );
+ if (err)
+ goto out;
+out:
+ dput(dentry);
+ dput(dentry_wh);
+ return err;
+}
+
+
/*
* Initialize any odf data we might need
* Reads the odf file from the options
@@ -6,58 +87,84 @@
struct odf_sb_info* odf_read_super(char *options)
{
struct nameidata nd;
- struct odf_sb_info *osi;
+ struct odf_sb_info *osi = NULL;
char *odffile = NULL;
struct sioa_args *sioa;
- int err, odfforce;
+ int err, odfforce, new = 0;
odfforce = odf_parse_options(options, &odffile);
if (odfforce < 0) {
- osi = ERR_PTR(odfforce);
+ err = odfforce;
goto out;
}
err = path_lookup(odffile, LOOKUP_FOLLOW, &nd);
if (err) {
- printk(KERN_WARNING "unionfs_odf: Cannot access odf\n");
- osi = ERR_PTR(err);
+ printk(KERN_WARNING "unionfs: Cannot access odf\n");
goto out;
}
-
- err = odf_is_odf(nd.dentry);
- if (err) {
- osi = ERR_PTR(err);
+ if (!nd.dentry->d_inode || !S_ISDIR(nd.dentry->d_inode->i_mode)) {
+ printk(KERN_WARNING "unionfs: Invalid odf\n");
+ err = -EINVAL;
goto out_release;
}
+
+ /* if this odf is fresh, create the hierarchy */
+ if (check_empty_lower(nd.dentry, nd.mnt) == 0) {
+ err = __odf_create_hierarchy(nd.dentry);
+ if (err)
+ goto out_release;
+ new = 1;
+ }
osi = kzalloc(sizeof(struct odf_sb_info), GFP_KERNEL);
if (!osi) {
- osi = ERR_PTR(-ENOMEM);
+ err = -ENOMEM;
goto out_release;
}
+
osi->odi_ns = odf_getpath(nd.dentry, osi, ODF_NS);
if (IS_ERR(osi->odi_ns)){
err = PTR_ERR(osi->odi_ns);
osi->odi_ns = NULL;
goto out_free;
}
+ if (!osi->odi_ns) {
+ err = -EINVAL;
+ goto out_free;
+ }
+
osi->odi_sb = odf_getpath(nd.dentry, osi, ODF_SB);
if (IS_ERR(osi->odi_sb)){
err = PTR_ERR(osi->odi_sb);
osi->odi_sb = NULL;
goto out_free;
}
+ if (!osi->odi_sb) {
+ err = -EINVAL;
+ goto out_free;
+ }
osi->odi_rc = odf_getpath(nd.dentry, osi, ODF_RC);
if (IS_ERR(osi->odi_rc)){
err = PTR_ERR(osi->odi_rc);
osi->odi_rc = NULL;
goto out_free;
}
+ if (!osi->odi_rc) {
+ err = -EINVAL;
+ goto out_free;
+ }
+
osi->odi_ic = odf_getpath(nd.dentry, osi, ODF_IC);
if (IS_ERR(osi->odi_ic)){
err = PTR_ERR(osi->odi_ic);
osi->odi_ic = NULL;
goto out_free;
}
+ if (!osi->odi_ic) {
+ err = -EINVAL;
+ goto out_free;
+ }
+
osi->whiteout = lookup_one_len(ODF_WH_NAME, osi->odi_sb->dentry,
ODF_WH_LEN);
if (IS_ERR(osi->whiteout)) {
err = PTR_ERR(osi->whiteout);
@@ -65,10 +172,16 @@ struct odf_sb_info* odf_read_super(char *options)
goto out_free;
}
if (!osi->whiteout->d_inode) {
- err = vfs_create(osi->odi_sb->dentry->d_inode, osi->whiteout,
S_IRWXUGO, NULL );
- if (err)
- goto out_free;
+ err = -EINVAL;
+ goto out_free;
}
+
+ /* if this odf was not fresh, but doesn't have sb/content, then fail */
+ if (!new && odf_is_new(osi)) {
+ err = -EINVAL;
+ goto out_free;
+ }
+
/* start the reclaim sioa */
sioa = kmalloc(sizeof(struct sioa_args), GFP_KERNEL);
if (!sioa) {
@@ -93,10 +206,11 @@ out_free:
dput(osi->whiteout);
kfree(osi->branch_uuids);
kfree(osi);
- osi = ERR_PTR(err);
out_release:
path_release(&nd);
out:
+ if (err)
+ osi = ERR_PTR(err);
kfree(odffile);
return osi;
@@ -137,6 +251,7 @@ struct odf_dentry_info* odf_getpath(struct dentry *d_odf,
struct odf_sb_info *os
else if (!dentry->d_inode) {
odi = ERR_PTR(-EINVAL);
dput(dentry);
+ goto out;
}
odi = odf_fill_info(NULL, osi, dentry);
dput(dentry);
@@ -144,39 +259,6 @@ out:
return odi;
}
-/*
- * Returns 0 if the given path is a valid odf file
- */
-int odf_is_odf(struct dentry *d_odf)
-{
- struct dentry *magic;
- int err = 0;
-
- if (!d_odf->d_inode) {
- err = -EINVAL;
- goto out;
- }
-
- if (!S_ISDIR(d_odf->d_inode->i_mode)) {
- err = -EINVAL;
- goto out;
- }
-
- magic = lookup_one_len(ODF_MAGIC_FILE, d_odf, strlen(ODF_MAGIC_FILE));
- if (IS_ERR(magic) || !magic) {
- err = -EINVAL;
- goto out;
- }
- else if (!magic->d_inode)
- err = -EINVAL;
-
- dput(magic);
-out:
- if (err)
- printk("unionfs: Invalid odf\n");
- return err;
-}
-
/* returns 1 if odfforce found, 0 if not */
int odf_parse_options(char *options, char **odf_path)
{
@@ -1342,42 +1424,23 @@ int __odf_set_opaque(struct inode *i, int branch)
}
/*
- * checks the newbit
+ * checks the sb/content file exists
*/
int odf_is_new(struct odf_sb_info *osi)
{
- struct dentry *newbit;
+ struct dentry *dentry;
- /* check the new bit, for now check if file newbit exists */
- newbit = lookup_one_len(ODF_NEWBIT, osi->odi_sb->dentry,
strlen(ODF_NEWBIT));
- if (IS_ERR(newbit) || !newbit)
- return 0;
- else if (likely(!newbit->d_inode)) {
- dput(newbit);
- return 0;
+ /* check if sb/content exists */
+ dentry = lookup_one_len(ODF_CONTENT, osi->odi_sb->dentry,
ODF_CONTENT_LEN);
+ if (IS_ERR(dentry) || !dentry)
+ return 1;
+ else if (unlikely(!dentry->d_inode)) {
+ dput(dentry);
+ return 1;
}
- dput(newbit);
- return 1;
-}
-
-/*
- * Unsets the newbit
- */
-void odf_unset_newbit(struct odf_sb_info *osi)
-{
- struct dentry *newbit;
-
- /* check the new bit, for now check if file newbit exists */
- newbit = lookup_one_len(ODF_NEWBIT, osi->odi_sb->dentry,
strlen(ODF_NEWBIT));
- if (IS_ERR(newbit) || !newbit)
- return;
- else if (unlikely(!newbit->d_inode)) {
- dput(newbit);
- return;
- }
- vfs_unlink(newbit->d_parent->d_inode, newbit);
- dput(newbit);
+ dput(dentry);
+ return 0;
}
/*
diff --git a/fs/unionfs/odf.h b/fs/unionfs/odf.h
index 086ec4b..aadda01 100644
--- a/fs/unionfs/odf.h
+++ b/fs/unionfs/odf.h
@@ -11,8 +11,6 @@
#define ODF_IC "ic"
#define ODF_RC "reclaim"
#define ODF_NS "ns"
-#define ODF_NEWBIT "newbit"
-#define ODF_MAGIC_FILE "odfmagic"
/* Some string constants */
#define ODF_BRANCH_PATH 255
@@ -54,12 +52,10 @@
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_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);
int odf_update_uuids(struct odf_sb_info *odf, struct path *old_paths, int
old_branches,
struct path *new_paths, int new_branches);
static inline char *odf_get_branch_uuid(struct odf_sb_info *odf, int branch)
diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
index c1b5f27..7bfc369 100644
--- a/fs/unionfs/union.h
+++ b/fs/unionfs/union.h
@@ -291,6 +291,7 @@ extern int unionfs_get_nlinks(struct inode *inode);
/* Is this directory empty: 0 if it is empty, -ENOTEMPTY if not. */
extern int check_empty(struct dentry *dentry,
struct unionfs_dir_state **namelist);
+extern int check_empty_lower(struct dentry *lower_dentry, struct vfsmount
*mnt);
/* Re-lookup a hidden dentry. */
extern int unionfs_refresh_hidden_dentry(struct dentry *dentry, int bindex);
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs