commit ef39c8489e656cb8ad28566e65a3dc5f8691c084
Author: Yiannis Pericleous <[EMAIL PROTECTED]>
Date: Wed Feb 7 14:38:33 2007 -0500
symlink, mknod to remove old whiteout
removed some old unlink code
new lookup flag to create dir as opaque
some locking
diff --git a/fs/unionfs/dirfops.c b/fs/unionfs/dirfops.c
index 89387de..f17d4d0 100644
--- a/fs/unionfs/dirfops.c
+++ b/fs/unionfs/dirfops.c
@@ -96,8 +96,7 @@ static int unionfs_filldir(void *dirent, const char *name,
int namelen,
buf->filldir_error = err;
out:
- if (odi)
- odf_clear_info(&odi);
+ odf_put_info(odi);
return err;
}
diff --git a/fs/unionfs/dirhelper.c b/fs/unionfs/dirhelper.c
index 3b43b79..afdb974 100644
--- a/fs/unionfs/dirhelper.c
+++ b/fs/unionfs/dirhelper.c
@@ -153,7 +153,7 @@ static int readdir_util_callback(void *dirent, const char
*name, int namelen,
if (name[0] == '.' && (namelen == 1 || (name[1] == '.' && namelen ==
2)))
goto out;
- /* check odf odf */
+ /* check odf */
odi = odf_lookup_name(buf->dir, name, namelen, 0);
if (IS_ERR(odi)){
odi = NULL;
@@ -184,8 +184,7 @@ static int readdir_util_callback(void *dirent, const char
*name, int namelen,
buf->rdstate->bindex, whiteout);
out:
- if (odi)
- odf_clear_info(&odi);
+ odf_put_info(odi);
buf->err = err;
return err;
}
diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
index 9a9687c..303ef86 100644
--- a/fs/unionfs/inode.c
+++ b/fs/unionfs/inode.c
@@ -192,7 +192,8 @@ static int unionfs_create(struct inode *parent, struct
dentry *dentry,
break;
} else {
UNIONFS_D(dentry)->odf_info =
- odf_lookup(dentry->d_parent, dentry,
ODF_LOOKUP_FILE|ODF_LOOKUP_RMV_WH);
+ odf_lookup(dentry->d_parent, dentry,
+ ODF_LOOKUP_FILE|ODF_LOOKUP_RMV_WH);
err = unionfs_interpose(dentry, parent->i_sb, 0);
if (!err) {
fsstack_copy_attr_times(parent,
@@ -470,6 +471,10 @@ static int unionfs_symlink(struct inode *dir, struct
dentry *dentry,
if (!IS_COPYUP_ERR(err))
break;
} else {
+ /* update odf and remove any wh before interpose*/
+ UNIONFS_D(dentry)->odf_info =
+ odf_lookup(dentry->d_parent, dentry,
+ ODF_LOOKUP_FILE|ODF_LOOKUP_RMV_WH);
err = unionfs_interpose(dentry, dir->i_sb, 0);
if (!err) {
fsstack_copy_attr_times(dir,
@@ -704,6 +709,10 @@ static int unionfs_mknod(struct inode *dir, struct dentry
*dentry, int mode,
unlock_dir(hidden_parent_dentry);
break;
}
+ /* update odf and remove any wh before interpose*/
+ UNIONFS_D(dentry)->odf_info =
+ odf_lookup(dentry->d_parent, dentry,
+ ODF_LOOKUP_FILE|ODF_LOOKUP_RMV_WH);
err = unionfs_interpose(dentry, dir->i_sb, 0);
if (!err) {
diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
index 91213bf..59532ee 100644
--- a/fs/unionfs/lookup.c
+++ b/fs/unionfs/lookup.c
@@ -448,7 +448,7 @@ void free_dentry_private_data(struct unionfs_dentry_info
*udi)
{
if (!udi)
return;
- odf_clear_info(&udi->odf_info);
+ odf_put_info(udi->odf_info);
kmem_cache_free(unionfs_dentry_cachep, udi);
}
diff --git a/fs/unionfs/odf.c b/fs/unionfs/odf.c
index c7603ef..a864b96 100644
--- a/fs/unionfs/odf.c
+++ b/fs/unionfs/odf.c
@@ -112,13 +112,16 @@ int odf_reclaim(struct dentry *dentry)
}
sprintf(new_name,"%lu", dentry->d_inode->i_ino);
+ /* lock new dir, the old dir should already be locked */
+ odf_lock(odi);
+
old_dentry = dentry;
old_dir = dentry->d_parent->d_inode;
new_dir = odi->dentry->d_inode;
new_dentry = lookup_one_len(new_name, odi->dentry, strlen(new_name));
- if(IS_ERR(new_dentry)){
+ if (IS_ERR(new_dentry)) {
err = PTR_ERR(new_dentry);
- goto out;
+ goto out_unlock;
}
/* this should never happen */
@@ -126,53 +129,71 @@ int odf_reclaim(struct dentry *dentry)
err = vfs_rename(old_dir, old_dentry, new_dir, new_dentry);
dput(new_dentry);
+
+out_unlock:
+ odf_unlock(odi); /* unlock new dir */
+
out:
kfree(new_name);
- if (odi)
- odf_clear_info(&odi);
+ odf_put_info(odi);
return err;
}
/*
- * Lookup an entry in the odf, create it if not found,
- * else check for whiteouts
- * Handle hard links
+ * Lookup an entry in the odf, and create it if necessary
+ * Returns a an odf_dentry_info containing whiteout and
+ * opaqueness information. Also handles hard links.
+ * If no flags are set and lookup fails, NULL is returned
+ * The function puts the dentry's odf_info and NULL's it
+ * Flags:
+ * - None set: lookup does not create any new entries
+ * - ODF_LOOKUP_FILE: create a file entry if lookup fails
+ * - ODF_LOOKUP_DIR: create a dir if lookup fails
+ * - ODF_LOOKUP_RMV_WH: if lookup returns a wh, remove it
+ * (useful for create where we want to rmv wh's)
+ * - ODF_LOOKUP_OPQ: if a dir is created, set it opaque (branch 0)
*/
struct odf_dentry_info *odf_lookup(struct dentry *parent, struct dentry
*dentry, int flags)
{
- if (UNIONFS_D(dentry)->odf_info)
- odf_clear_info(&UNIONFS_D(dentry)->odf_info);
-
+ odf_put_info(UNIONFS_D(dentry)->odf_info);
+ UNIONFS_D(dentry)->odf_info = NULL;
return odf_lookup_name(parent, dentry->d_name.name, dentry->d_name.len,
flags);
}
-struct odf_dentry_info *odf_lookup_name(struct dentry *parent, const char
*name, int len, int flags)
+
+struct odf_dentry_info *odf_lookup_name(struct dentry *parent, const char
*name,
+ int len, int
flags)
{
- struct dentry *odf_dentry = NULL;
+ struct dentry *odf_dentry;
struct odf_dentry_info *odi = NULL;
struct inode *odf_i_dir = UNIONFS_D(parent)->odf_info->dentry->d_inode;
int err = 0;
- odf_dentry = lookup_one_len(name, UNIONFS_D(parent)->odf_info->dentry,
len);
+ odf_dentry = lookup_one_len(name,
+ UNIONFS_D(parent)->odf_info->dentry, len);
/* if create flags are set, remove existing whiteout */
- if (!IS_ERR(odf_dentry) && odf_dentry->d_inode && (flags &
ODF_LOOKUP_RMV_WH))
+ if (!IS_ERR(odf_dentry)
+ && odf_dentry->d_inode
+ && (flags & ODF_LOOKUP_RMV_WH))
{
if (odf_is_wh_i(odf_dentry->d_inode)){
vfs_unlink(odf_i_dir, odf_dentry);
dput(odf_dentry);
- /* does this make sense? */
- odf_dentry = lookup_one_len(name,
UNIONFS_D(parent)->odf_info->dentry, len);
+ odf_dentry = lookup_one_len(name,
+ UNIONFS_D(parent)->odf_info->dentry, len);
}
}
/* create inode in odf if dont exist */
- /* XXX: should we fail if res is ERR? */
+ /* FIXME: should we fail if res is ERR? */
if (IS_ERR(odf_dentry) || !odf_dentry->d_inode) {
if (name[0]=='.')
BUG_ON(len==1 || (name[1]=='.'&&len==2));
/* FIXME need to check hardlinks before create */
+ odf_lock(UNIONFS_D(parent)->odf_info); /* lock parent */
+
if (flags & ODF_LOOKUP_FILE)
err = vfs_create(odf_i_dir, odf_dentry, S_IRWXUGO, 0 );
@@ -181,19 +202,24 @@ struct odf_dentry_info *odf_lookup_name(struct dentry
*parent, const char *name,
else {
dput(odf_dentry);
+ odf_unlock(UNIONFS_D(parent)->odf_info);
goto out;
}
if (err) {
- printk(KERN_WARNING "could not create odf dentry" );
+ printk(KERN_WARNING "odf_lookup: could not create odf
dentry" );
odi = ERR_PTR(err);
goto out;
}
- odf_set_opaque_i(odf_dentry->d_inode, -1);
+
+ odf_unlock(UNIONFS_D(parent)->odf_info);
+
+ /* set opaqueness to 0 or -1 */
+ odf_set_opaque_i(odf_dentry->d_inode,
+ -!(flags & ODF_LOOKUP_OPQ));
odf_set_wh_i(odf_dentry->d_inode,0);
-
}
else {
- /* FIXME check for whiteouts & hardlinks */
+ /* FIXME check for hardlinks */
}
odi = odf_fill_info(odf_dentry);
@@ -216,16 +242,18 @@ int odf_create_wh(struct dentry *dentry)
odf_dentry = UNIONFS_D(dentry)->odf_info->dentry;
if (odf_is_wh_i(odf_dentry->d_inode))
goto out; /* nothing to be done */
-
+
/* remove entry if existed */
err = odf_remove(dentry, ODF_RMV_ANY);
if (err)
goto out;
- odf_clear_info(&UNIONFS_D(dentry)->odf_info);
+ odf_put_info(UNIONFS_D(dentry)->odf_info);
/* now create a new file and make it a whiteout */
- UNIONFS_D(dentry)->odf_info = odf_lookup(dentry->d_parent, dentry,
ODF_LOOKUP_FILE);
+ UNIONFS_D(dentry)->odf_info =
+ odf_lookup(dentry->d_parent,
+ dentry, ODF_LOOKUP_FILE);
if (!UNIONFS_D(dentry)->odf_info){
err = PTR_ERR(UNIONFS_D(dentry)->odf_info); /* odf out of
space? */
goto out;
@@ -244,11 +272,12 @@ out:
*/
int odf_remove(struct dentry *dentry, int flags)
{
+ struct odf_dentry_info *odf_dir;
struct odf_dentry_info *odi = NULL;
int err = 0, rmv = 0;
BUG_ON(!UNIONFS_D(dentry)->odf_info);
-
+
/* refresh odi */
UNIONFS_D(dentry)->odf_info = odf_lookup(dentry->d_parent, dentry, 0);
odi = UNIONFS_D(dentry)->odf_info;
@@ -270,6 +299,9 @@ int odf_remove(struct dentry *dentry, int flags)
if (!rmv)
goto out;
+
+ odf_dir = UNIONFS_D(dentry->d_parent)->odf_info;
+ odf_lock(odf_dir);
/* remove */
if (S_ISDIR(odi->dentry->d_inode->i_mode))
@@ -277,19 +309,22 @@ int odf_remove(struct dentry *dentry, int flags)
else
err = vfs_unlink(odi->dentry->d_parent->d_inode, odi->dentry);
if (err)
- goto out;
+ goto out_unlock;
/* clean up */
- odf_clear_info(&UNIONFS_D(dentry)->odf_info);
+ odf_put_info(UNIONFS_D(dentry)->odf_info);
+out_unlock:
+ odf_unlock(odf_dir);
out:
return err;
}
/*
- * Sets the whiteout flag
+ * Sets the whiteout flag, the boolean decides whether to set whiteout on/off
* The dentry version takes a UnionFS dentry, the inode one an ODF inode
*/
+/* FIXME: for the following functions can we count on EXT2 to do the locking?
*/
int odf_set_wh(struct dentry *dentry, int boolean)
{
int err = odf_set_wh_i(UNIONFS_D(dentry)->odf_info->dentry->d_inode,
boolean);
@@ -303,7 +338,7 @@ int odf_set_wh_i(struct inode *i, int boolean)
if (boolean)
EXT2_I(i)->i_flags |= ODF_WHITEOUT;
else
- EXT2_I(i)->i_flags &= !ODF_WHITEOUT;
+ EXT2_I(i)->i_flags &= ~ODF_WHITEOUT;
err = ext2_write_inode(i, 1);
return err;
}
@@ -366,18 +401,19 @@ int odf_get_opaque_i(struct inode *i)
*/
int odf_set_opaque(struct dentry *dentry, int branch)
{
- int err =
odf_set_opaque_i(UNIONFS_D(dentry)->odf_info->dentry->d_inode, branch);
+ struct odf_dentry_info *odi = UNIONFS_D(dentry)->odf_info;
+ int err = odf_set_opaque_i(odi->dentry->d_inode, branch);
if (!err)
- UNIONFS_D(dentry)->odf_info->opaque = branch;
+ odi->opaque = branch;
return err;
}
+
int odf_set_opaque_i(struct inode *i, int branch)
{
u32 b = branch;
int err = 0;
-
if (branch < 0)
- EXT2_I(i)->i_flags &= !ODF_OPAQUE;
+ EXT2_I(i)->i_flags &= ~ODF_OPAQUE;
else {
b <<= ODF_OPQ_BASE + 1;
b >>= 1;
@@ -388,7 +424,7 @@ int odf_set_opaque_i(struct inode *i, int branch)
}
/*
- * returns the dirs= part of the mount options
+ * returns the dirs= part of the mount options
*/
char *odf_getoptions(void)
{
@@ -587,25 +623,26 @@ out:
*/
struct odf_dentry_info *odf_fill_info(struct dentry *odf_dentry)
{
- struct odf_dentry_info *odi = kzalloc(sizeof(struct
odf_dentry_info),GFP_KERNEL);
+ struct odf_dentry_info *odi =
+ kzalloc(sizeof(struct odf_dentry_info),GFP_KERNEL);
odi->whiteout = odf_is_wh_i(odf_dentry->d_inode);
odi->opaque = odf_get_opaque_i(odf_dentry->d_inode);
odi->dentry = odf_dentry;
odi->inum = odf_dentry->d_inode->i_ino;
dget(odf_dentry);
+ mutex_init(&odi->lock);
return odi;
}
/*
* Clears the odf_info data
*/
-void odf_clear_info(struct odf_dentry_info **odi)
+void odf_put_info(struct odf_dentry_info *odi)
{
- if (!(*odi))
+ if (!odi)
return;
- dput((*odi)->dentry);
- kfree(*odi);
- *odi = NULL;
+ dput(odi->dentry);
+ kfree(odi);
}
diff --git a/fs/unionfs/odf.h b/fs/unionfs/odf.h
index 2fc01fd..004ebe2 100644
--- a/fs/unionfs/odf.h
+++ b/fs/unionfs/odf.h
@@ -19,6 +19,7 @@
#define ODF_LOOKUP_FILE 1
#define ODF_LOOKUP_DIR 2
#define ODF_LOOKUP_RMV_WH 4
+#define ODF_LOOKUP_OPQ 8
/* Unlink/Remove flags */
#define ODF_RMV_WH 1
@@ -43,7 +44,7 @@ struct odf_dentry_info *odf_lookup(struct dentry *parent,
struct dentry *dentry,
struct odf_dentry_info *odf_lookup_name(struct dentry *parent, const char
*name, int len, int flags);
struct odf_dentry_info *odf_getns(void);
struct odf_dentry_info *odf_fill_info(struct dentry *odf_dentry);
-void odf_clear_info(struct odf_dentry_info **odi);
+void odf_put_info(struct odf_dentry_info *odi);
/* unlink */
int odf_remove(struct dentry *dentry, int flags);
@@ -64,4 +65,16 @@ int odf_is_opaque_i(struct inode *i);
int odf_get_opaque_i(struct inode *i);
int odf_set_opaque_i(struct inode *i, int branch);
+/* Macros for locking an odf dentry info. */
+static inline void odf_lock(struct odf_dentry_info *odi)
+{
+ mutex_lock(&odi->lock);
+}
+
+static inline void odf_unlock(struct odf_dentry_info *odi)
+{
+ mutex_unlock(&odi->lock);
+}
+
+
#endif /* _ODF_H_ */
diff --git a/fs/unionfs/subr.c b/fs/unionfs/subr.c
index e563bbc..8d1ce32 100644
--- a/fs/unionfs/subr.c
+++ b/fs/unionfs/subr.c
@@ -37,10 +37,7 @@ int create_whiteout(struct dentry *dentry, int start)
/* odf whiteout */
err = odf_create_wh(dentry);
- if (err)
- goto out;
- else /*FIXME very creative and constructive if/else
*/
- goto out; /* to bypass the original whiteout code
*/
+ goto out; /* FIXME: bypass the original whiteout code */
/* create dentry's whiteout equivalent */
name = alloc_whname(dentry->d_name.name, dentry->d_name.len);
diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
index 6256aa0..d62453d 100644
--- a/fs/unionfs/union.h
+++ b/fs/unionfs/union.h
@@ -92,6 +92,7 @@ struct odf_dentry_info {
* the data in the odf file. Right now i keep a dentry for easy
* lookup in the underlying ext2
*/
+ struct mutex lock;
u64 inum;
int whiteout;
int opaque;
diff --git a/fs/unionfs/unlink.c b/fs/unionfs/unlink.c
index dc846db..8224d11 100644
--- a/fs/unionfs/unlink.c
+++ b/fs/unionfs/unlink.c
@@ -18,57 +18,6 @@
#include "union.h"
-/* unlink a file by creating a whiteout */
-static int unionfs_unlink_whiteout(struct inode *dir, struct dentry *dentry)
-{
- struct dentry *hidden_dentry;
- struct dentry *hidden_dir_dentry;
- int bindex;
- int err = 0;
-
- if ((err = unionfs_partial_lookup(dentry)))
- goto out;
-
- bindex = dbstart(dentry);
-
- hidden_dentry = unionfs_lower_dentry_idx(dentry, bindex);
- if (!hidden_dentry)
- goto out;
-
- hidden_dir_dentry = lock_parent(hidden_dentry);
-
- /* avoid destroying the hidden inode if the file is in use */
- dget(hidden_dentry);
- if (!(err = is_robranch_super(dentry->d_sb, bindex)))
- err = vfs_unlink(hidden_dir_dentry->d_inode, hidden_dentry);
- dput(hidden_dentry);
- fsstack_copy_attr_times(dir, hidden_dir_dentry->d_inode);
- unlock_dir(hidden_dir_dentry);
-
- if (err && !IS_COPYUP_ERR(err))
- goto out;
-
- if (err) {
- if (dbstart(dentry) == 0)
- goto out;
-
- err = create_whiteout(dentry, dbstart(dentry) - 1);
- } else if (dbopaque(dentry) != -1)
- /* There is a hidden lower-priority file with the same name. */
- err = create_whiteout(dentry, dbopaque(dentry));
- else
- err = create_whiteout(dentry, dbstart(dentry));
-
-out:
- if (!err)
- dentry->d_inode->i_nlink--;
-
- /* We don't want to leave negative leftover dentries for revalidate. */
- if (!err && (dbopaque(dentry) != -1))
- update_bstart(dentry);
-
- return err;
-}
static int unionfs_do_unlink(struct inode *dir, struct dentry *dentry)
{
struct dentry *hidden_dentry;
@@ -128,7 +77,6 @@ int unionfs_unlink(struct inode *dir, struct dentry *dentry)
unionfs_lock_dentry(dentry);
- //err = unionfs_unlink_whiteout(dir, dentry);
err = unionfs_do_unlink(dir, dentry);
/* call d_drop so the system "forgets" about us */
if (!err) {
@@ -145,38 +93,6 @@ int unionfs_unlink(struct inode *dir, struct dentry *dentry)
return err;
}
-static int unionfs_rmdir_first(struct inode *dir, struct dentry *dentry,
- struct unionfs_dir_state *namelist)
-{
- int err;
- struct dentry *hidden_dentry;
- struct dentry *hidden_dir_dentry = NULL;
-
- /* Here we need to remove whiteout entries. */
- err = delete_whiteouts(dentry, dbstart(dentry), namelist);
- if (err)
- goto out;
-
- hidden_dentry = unionfs_lower_dentry(dentry);
-
- hidden_dir_dentry = lock_parent(hidden_dentry);
-
- /* avoid destroying the hidden inode if the file is in use */
- dget(hidden_dentry);
- if (!(err = is_robranch(dentry)))
- err = vfs_rmdir(hidden_dir_dentry->d_inode, hidden_dentry);
- dput(hidden_dentry);
-
- fsstack_copy_attr_times(dir, hidden_dir_dentry->d_inode);
- /* propagate number of hard-links */
- dentry->d_inode->i_nlink = unionfs_get_nlinks(dentry->d_inode);
-
-out:
- if (hidden_dir_dentry)
- unlock_dir(hidden_dir_dentry);
- return err;
-}
-
static int unionfs_do_rmdir(struct inode *dir, struct dentry *dentry)
{
struct dentry *hidden_dentry;
@@ -239,7 +155,6 @@ int unionfs_rmdir(struct inode *dir, struct dentry *dentry)
if (err)
goto out;
-// err = unionfs_rmdir_first(dir, dentry, namelist);
err = unionfs_do_rmdir(dir, dentry);
if (err)
goto out;
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs