commit 887852612597cf8f4aa55ead2ee75ea31f4aa0fc
Author: Yiannis Pericleous <[EMAIL PROTECTED]>
Date: Sat Mar 17 20:40:58 2007 -0400
cleanup thread to always cleanup odf/ic whenever it wakes up.
odf_lookup wakes up cleanup thread when out of space
added an odf_sb_info field to odf_dentry_info (for locking whole odf)
diff --git a/fs/unionfs/commonfops.c b/fs/unionfs/commonfops.c
index 9754d8d..eba60ca 100644
--- a/fs/unionfs/commonfops.c
+++ b/fs/unionfs/commonfops.c
@@ -168,7 +168,8 @@ int unionfs_silly_rename(struct dentry *dentry, struct
dentry *hidden_dentry)
goto out;
/* create a whiteout */
- odi = __odf_lookup(UNIONFS_D(dentry->d_parent)->odf_info,
+ odi = __odf_lookup(UNIONFS_D(dentry->d_parent)->odf_info,
+ UNIONFS_SB(dentry->d_sb)->odf,
name, strlen(name), ODF_LOOKUP_WH, odi);
BUG_ON(IS_ERR(odi) || odi == NULL);
out:
diff --git a/fs/unionfs/dirhelper.c b/fs/unionfs/dirhelper.c
index 8901708..dce4b3e 100644
--- a/fs/unionfs/dirhelper.c
+++ b/fs/unionfs/dirhelper.c
@@ -22,6 +22,10 @@
#define RD_CHECK_EMPTY 1
#define RD_CACHE_ODF 2
#define RD_CHECK_HD_EMPTY 3
+
+#define RM_ALL 0
+#define RM_LEAF 1
+
/* The callback structure for check_empty. */
struct unionfs_rdutil_callback {
int err;
@@ -36,6 +40,8 @@ struct unionfs_rmdir_callback {
int filldir_called;
struct dentry *dir;
struct vfsmount *mnt;
+ int isleaf;
+ int mode;
};
static int rmdir_util_callback(void *dirent, const char *name, int namelen,
loff_t offset, u64 ino, unsigned int d_type)
@@ -57,9 +63,12 @@ static int rmdir_util_callback(void *dirent, const char
*name, int namelen,
}
else if (!dentry->d_inode)
BUG_ON(1); /*can this ever happen?*/
-
- if (d_type == DT_DIR)
- err = unionfs_force_rmdir(buf->mnt, dentry, 1);
+
+ if (d_type == DT_DIR) {
+ buf->isleaf = 0;
+ err = unionfs_force_rmdir(buf->mnt, dentry,
+ buf->mode == RM_LEAF ? FRMV_LEAF : FRMV_ALL);
+ }
else
err = vfs_unlink(buf->dir->d_inode, dentry);
dput(dentry);
@@ -109,7 +118,9 @@ static int readdir_util_callback(void *dirent, const char
*name, int namelen,
/* check odf */
/* XXX: lookup might require to lock it, so unlock for now */
odf_unlock(UNIONFS_D(buf->dir)->odf_info);
- odi = __odf_lookup(UNIONFS_D(buf->dir)->odf_info, name, namelen,
create_flag, 0);
+ odi = __odf_lookup(UNIONFS_D(buf->dir)->odf_info,
+ UNIONFS_SB(buf->dir->d_sb)->odf,
+ name, namelen, create_flag, 0);
odf_lock(UNIONFS_D(buf->dir)->odf_info);
if (IS_ERR(odi)){
odi = NULL;
@@ -374,12 +385,15 @@ out:
}
/* This function recursively rermoves all the entries of a lower directory
- * at a specific branch and then the directory itself if rm_parent is set. It
- * does not cross branches, and does nothing visible to the union. It should
- * only be used when both a whiteout and a dir at top branch exists
- * and we need to create a new dentry or in the odf
+ * at a specific branch and then the directory itself. It does not cross
+ * branches, and does nothing visible to the union. It should only be used
+ * when both a whiteout and a dir at top branch exists and we need to create
+ * create a new dentry or in the odf for cleanup
+ * Flags: RMV_ALL : removes all entries
+ * RMV_LEAF : removes dirs only if they are leaves (dont have
subdirs)
+ * RMV_NOTPARENT : can be set with both flags above, does not rmv
base dir
*/
-int unionfs_force_rmdir(struct vfsmount *mnt, struct dentry *hidden_dentry,
int rm_parent)
+int unionfs_force_rmdir(struct vfsmount *mnt, struct dentry *hidden_dentry,
int flags)
{
int err = 0;
struct file *hidden_file;
@@ -393,6 +407,11 @@ int unionfs_force_rmdir(struct vfsmount *mnt, struct
dentry *hidden_dentry, int
buf->err = 0;
buf->dir = hidden_dentry;
buf->mnt = mnt;
+ buf->isleaf = 1;
+ if (flags & FRMV_LEAF)
+ buf->mode = RM_LEAF;
+ else
+ buf->mode = RM_ALL;
if (!hidden_dentry->d_inode)
goto out;
@@ -414,15 +433,16 @@ int unionfs_force_rmdir(struct vfsmount *mnt, struct
dentry *hidden_dentry, int
if (buf->err)
err = buf->err;
} while ((err >= 0) && buf->filldir_called);
-
+
/* fput calls dput for hidden_dentry */
fput(hidden_file);
if (err < 0)
goto out;
- if (rm_parent)
- err = vfs_rmdir(hidden_dentry->d_parent->d_inode,
hidden_dentry);
+ if ((flags & FRMV_NOTPARENT) || ((flags & FRMV_LEAF) && !buf->isleaf))
+ goto out;
+ err = vfs_rmdir(hidden_dentry->d_parent->d_inode, hidden_dentry);
out:
kfree(buf);
diff --git a/fs/unionfs/odf.c b/fs/unionfs/odf.c
index 1a19c69..d262c73 100644
--- a/fs/unionfs/odf.c
+++ b/fs/unionfs/odf.c
@@ -35,25 +35,25 @@ struct odf_sb_info* odf_read_super(char *options)
osi = ERR_PTR(-ENOMEM);
goto out_release;
}
- osi->odi_ns = odf_getpath(nd.dentry, ODF_NS);
+ 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;
}
- osi->odi_sb = odf_getpath(nd.dentry, ODF_SB);
+ 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;
}
- osi->odi_rc = odf_getpath(nd.dentry, ODF_RC);
+ 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;
}
- osi->odi_ic = odf_getpath(nd.dentry, ODF_IC);
+ 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;
@@ -66,9 +66,9 @@ struct odf_sb_info* odf_read_super(char *options)
err = -ENOMEM;
goto out_free;
}
- sioa->reclaim.odf = osi;
- osi->sioa = sioa;
- run_sioa(sioa, __odf_reclaim_w, __odf_reclaim_d, ODF_RC_TIMEOUT);
+ sioa->cleanup.odf = osi;
+ osi->cleanup = sioa;
+ run_sioa(sioa, __odf_cleanup_w, __odf_cleanup_d, ODF_RC_TIMEOUT);
osi->mnt = nd.mnt;
mntget(osi->mnt);
@@ -104,9 +104,9 @@ void odf_put_super(struct odf_sb_info *osi)
dput(osi->mnt->mnt_sb->s_root);
mntput(osi->mnt);
osi->odi_rc = NULL;
- wake_up_sioa(osi->sioa);
- wait_for_sioa(osi->sioa);
- kfree(osi->sioa);
+ wake_up_sioa(osi->cleanup);
+ wait_for_sioa(osi->cleanup);
+ kfree(osi->cleanup);
}
/*
@@ -114,7 +114,7 @@ void odf_put_super(struct odf_sb_info *osi)
* This is to be used for accessing whatever is in the root of the
* odf, ie /odf/ic, /odf/ns, etc
*/
-struct odf_dentry_info* odf_getpath(struct dentry *d_odf, const char *name)
+struct odf_dentry_info* odf_getpath(struct dentry *d_odf, struct odf_sb_info
*osi, const char *name)
{
struct dentry *dentry;
struct odf_dentry_info* odi = NULL;
@@ -128,7 +128,7 @@ struct odf_dentry_info* odf_getpath(struct dentry *d_odf,
const char *name)
odi = ERR_PTR(-EINVAL);
dput(dentry);
}
- odi = odf_fill_info(NULL, dentry);
+ odi = odf_fill_info(NULL, osi, dentry);
dput(dentry);
out:
return odi;
@@ -369,6 +369,7 @@ int odf_lookup(struct dentry *parent, struct dentry
*dentry, int flags)
int err = 0;
UNIONFS_D(dentry)->odf_info = __odf_lookup(
UNIONFS_D(parent)->odf_info,
+ UNIONFS_SB(dentry->d_sb)->odf,
dentry->d_name.name,
dentry->d_name.len,
flags,
@@ -380,13 +381,13 @@ int odf_lookup(struct dentry *parent, struct dentry
*dentry, int flags)
return err;
}
-struct odf_dentry_info *__odf_lookup(struct odf_dentry_info *parent, const
char *name,
+struct odf_dentry_info *__odf_lookup(struct odf_dentry_info *parent, struct
odf_sb_info *osi, const char *name,
int len, int flags, struct
odf_dentry_info *old_odi)
{
struct dentry *odf_dentry;
struct odf_dentry_info *odi = old_odi;
struct inode *odf_i_dir = parent->dentry->d_inode;
- int opaque, whiteout, err = 0;
+ int opaque, whiteout, err = 0, cleaned = 0;
uid_t olduid;
gid_t oldgid;
@@ -420,11 +421,13 @@ struct odf_dentry_info *__odf_lookup(struct
odf_dentry_info *parent, const char
if (name[0]=='.')
BUG_ON(len==1 || (name[1]=='.'&&len==2));
-
+retry:
olduid = current->fsuid;
oldgid = current->fsgid;
/* FIXME need to check hardlinks before create */
+ if (osi->odi_ic != parent)
+ odf_lock(osi->odi_ic);
odf_lock(parent); /* lock parent */
if (flags & ODF_LOOKUP_FILE || flags & ODF_LOOKUP_WH) {
@@ -440,16 +443,27 @@ struct odf_dentry_info *__odf_lookup(struct
odf_dentry_info *parent, const char
else {
dput(odf_dentry);
odf_unlock(parent);
+ if (osi->odi_ic != parent)
+ odf_unlock(osi->odi_ic);
odf_put_info(old_odi);
odi = NULL;
goto out;
}
odf_unlock(parent);
+ if (osi->odi_ic != parent)
+ odf_unlock(osi->odi_ic);
current->fsuid = oldgid;
current->fsgid = olduid;
if (err) {
+ if (err == -ENOSPC && !cleaned) {
+ /* let the cleanup thread do its work and retry
once */
+ cleaned = 1;
+ wake_up_sioa(osi->cleanup);
+ schedule();
+ goto retry;
+ }
printk(KERN_WARNING "odf_lookup: could not create odf
dentry %s, %d\n", name, err);
dput(odf_dentry);
odf_put_info(old_odi);
@@ -467,7 +481,7 @@ struct odf_dentry_info *__odf_lookup(struct odf_dentry_info
*parent, const char
/* FIXME check for hardlinks */
}
- odi = odf_fill_info(old_odi, odf_dentry);
+ odi = odf_fill_info(old_odi, osi, odf_dentry);
dput(odf_dentry); /* since we dget in fill_info */
out:
return odi;
@@ -480,6 +494,7 @@ out:
struct odf_dentry_info *odf_ic_dir(struct dentry *dir)
{
struct odf_dentry_info *odi_dir, *odis[4], *odi_ic, *odi_ret = NULL;
+ struct odf_sb_info *osi;
u64 ino;
int breakdown[4];
char name[6];
@@ -489,7 +504,8 @@ struct odf_dentry_info *odf_ic_dir(struct dentry *dir)
err = -ENOTDIR;
goto out;
}
- odi_ic = UNIONFS_SB(dir->d_sb)->odf->odi_ic;
+ osi = UNIONFS_SB(dir->d_sb)->odf;
+ odi_ic = osi->odi_ic;
odi_dir = UNIONFS_D(dir)->odf_info;
if (!odi_dir) {
err = -ENOENT;
@@ -505,7 +521,7 @@ struct odf_dentry_info *odf_ic_dir(struct dentry *dir)
memset(name,0,6);
sprintf(name, "%x", breakdown[0]);
- odis[0] = __odf_lookup(odi_ic, name, strlen(name), ODF_LOOKUP_DIR,
NULL);
+ odis[0] = __odf_lookup(odi_ic, osi, name, strlen(name), ODF_LOOKUP_DIR,
NULL);
if (IS_ERR(odis[0])) {
err = PTR_ERR(odis[0]);
odis[0] = NULL;
@@ -514,7 +530,7 @@ struct odf_dentry_info *odf_ic_dir(struct dentry *dir)
for (i = 1; i < 4; i++) {
memset(name,0,6);
sprintf(name, "%x", breakdown[i]);
- odis[i] = __odf_lookup(odis[i-1], name, strlen(name),
ODF_LOOKUP_DIR, NULL);
+ odis[i] = __odf_lookup(odis[i-1], osi, name, strlen(name),
ODF_LOOKUP_DIR, NULL);
if (IS_ERR(odis[i])) {
err = PTR_ERR(odis[i]);
odis[i] = NULL;
@@ -522,7 +538,7 @@ struct odf_dentry_info *odf_ic_dir(struct dentry *dir)
}
}
- odi_ret = __odf_lookup(odis[3], "content", 7, ODF_LOOKUP_FILE, NULL);
+ odi_ret = __odf_lookup(odis[3], osi, "content", 7, ODF_LOOKUP_FILE,
NULL);
if (IS_ERR(odi_ret)) {
err = PTR_ERR(odi_ret);
odi_ret = NULL;
@@ -1120,7 +1136,7 @@ out:
/*
* Allocates an odi and fills it with inode and dentry
*/
-struct odf_dentry_info *odf_alloc_info(struct dentry *odf_dentry)
+struct odf_dentry_info *odf_alloc_info(struct odf_sb_info *osi, struct dentry
*odf_dentry)
{
struct odf_dentry_info *odi =
kzalloc(sizeof(struct odf_dentry_info),GFP_KERNEL);
@@ -1128,20 +1144,22 @@ struct odf_dentry_info *odf_alloc_info(struct dentry
*odf_dentry)
odi->opaque = __odf_get_opaque(odf_dentry->d_inode);
odi->dentry = odf_dentry;
odi->inum = odf_dentry->d_inode->i_ino;
+ odi->osi = osi;
dget(odf_dentry);
mutex_init(&odi->lock);
return odi;
}
-struct odf_dentry_info *odf_fill_info(struct odf_dentry_info *odi, struct
dentry *odf_dentry)
+struct odf_dentry_info *odf_fill_info(struct odf_dentry_info *odi, struct
odf_sb_info *osi, struct dentry *odf_dentry)
{
if (!odi)
- return odf_alloc_info(odf_dentry);
+ return odf_alloc_info(osi, odf_dentry);
odi->whiteout = __odf_is_wh(odf_dentry->d_inode);
odi->opaque = __odf_get_opaque(odf_dentry->d_inode);
dget(odf_dentry);
dput(odi->dentry);
odi->dentry = odf_dentry;
odi->inum = odf_dentry->d_inode->i_ino;
+ odi->osi = osi;
return odi;
}
@@ -1160,25 +1178,35 @@ void odf_put_info(struct odf_dentry_info *odi)
* Worker function for the cleanup thread. It recursively removes all entries
* in the reclaim directory
*/
-void __odf_reclaim_w(void *args)
+void __odf_cleanup_w(void *args)
{
- struct sioa_args *sioa_args = (struct sioa_args *)args;
- struct reclaim_args *rc = &sioa_args->reclaim;
- struct odf_dentry_info *odi_rc;
+ struct sioa_args *sioa_args = (struct sioa_args *)args;
+ struct cleanup_args *cl = &sioa_args->cleanup;
+ struct odf_dentry_info *odi_rc, *odi_ic;
+ struct kstatfs stat;
+
+ /* FIXME: only cleanup ic if certain % of space used */
+ /* XXX: what about when only no free inodes left but lots of space? */
+ vfs_statfs(cl->odf->odi_sb->dentry, &stat);
+
+ odi_ic = cl->odf->odi_ic;
+ odf_lock(odi_ic);
+ unionfs_force_rmdir(cl->odf->mnt, odi_ic->dentry,
FRMV_NOTPARENT|FRMV_LEAF);
+ odf_unlock(odi_ic);
- odi_rc = rc->odf->odi_rc;
+ odi_rc = cl->odf->odi_rc;
odf_lock(odi_rc);
- unionfs_force_rmdir(rc->odf->mnt, odi_rc->dentry, 0);
+ unionfs_force_rmdir(cl->odf->mnt, odi_rc->dentry, FRMV_NOTPARENT);
odf_unlock(odi_rc);
}
/*
* done function for the cleanup thread. It returns true if the odf is umounted
*/
-int __odf_reclaim_d(void *args)
+int __odf_cleanup_d(void *args)
{
- struct sioa_args *sioa_args = (struct sioa_args *)args;
- struct reclaim_args *rc = &sioa_args->reclaim;
- return !(rc->odf && rc->odf->odi_rc);
+ struct sioa_args *sioa_args = (struct sioa_args *)args;
+ struct cleanup_args *cl = &sioa_args->cleanup;
+ return !(cl->odf && cl->odf->odi_rc);
}
diff --git a/fs/unionfs/odf.h b/fs/unionfs/odf.h
index 30de795..dd7b3f9 100644
--- a/fs/unionfs/odf.h
+++ b/fs/unionfs/odf.h
@@ -53,11 +53,11 @@ int odf_is_odf(struct dentry *d_odf);
/* lookup */
int odf_lookup(struct dentry *parent, struct dentry *dentry, int flags);
-struct odf_dentry_info *__odf_lookup(struct odf_dentry_info *parent, const
char *name, int len, int flags, struct odf_dentry_info *old_odi);
+struct odf_dentry_info *__odf_lookup(struct odf_dentry_info *parent, struct
odf_sb_info *osi, const char *name, int len, int flags, struct odf_dentry_info
*old_odi);
-struct odf_dentry_info *odf_getpath(struct dentry *d_odf,const char *name);
-struct odf_dentry_info *odf_fill_info(struct odf_dentry_info *odi, struct
dentry *odf_dentry);
-struct odf_dentry_info *odf_alloc_info(struct dentry *odf_dentry);
+struct odf_dentry_info *odf_getpath(struct dentry *d_odf, struct odf_sb_info
*osi, const char *name);
+struct odf_dentry_info *odf_fill_info(struct odf_dentry_info *odi, struct
odf_sb_info *osi, struct dentry *odf_dentry);
+struct odf_dentry_info *odf_alloc_info(struct odf_sb_info *osi, struct dentry
*odf_dentry);
void odf_put_info(struct odf_dentry_info *odi);
/* dirents & dir cache */
@@ -90,8 +90,8 @@ int __odf_get_opaque(struct inode *i);
int __odf_set_opaque(struct inode *i, int branch);
/* cleanup thread functions */
-extern void __odf_reclaim_w(void *args);
-extern int __odf_reclaim_d(void *args);
+extern void __odf_cleanup_w(void *args);
+extern int __odf_cleanup_d(void *args);
/* Macros for locking an odf dentry info. */
static inline void odf_lock(struct odf_dentry_info *odi)
diff --git a/fs/unionfs/sioq.h b/fs/unionfs/sioq.h
index fd65ad0..cfc0ba4 100644
--- a/fs/unionfs/sioq.h
+++ b/fs/unionfs/sioq.h
@@ -33,7 +33,7 @@ struct unlink_args {
struct dentry *dentry;
};
-struct reclaim_args {
+struct cleanup_args {
struct odf_sb_info *odf;
};
@@ -60,7 +60,7 @@ struct sioa_args {
int (*done) (void*);
union {
- struct reclaim_args reclaim;
+ struct cleanup_args cleanup;
};
};
diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h
index 395824d..2752479 100644
--- a/fs/unionfs/union.h
+++ b/fs/unionfs/union.h
@@ -97,6 +97,7 @@ struct odf_dentry_info {
int whiteout;
int opaque;
struct dentry *dentry;
+ struct odf_sb_info *osi;
};
/* odf sb data */
@@ -106,7 +107,7 @@ struct odf_sb_info {
struct odf_dentry_info *odi_sb;
struct odf_dentry_info *odi_rc;
struct odf_dentry_info *odi_ic;
- struct sioa_args *sioa;
+ struct sioa_args *cleanup;
};
/* unionfs inode data in memory */
@@ -312,10 +313,15 @@ int unionfs_unlink(struct inode *dir, struct dentry
*dentry);
int unionfs_rmdir(struct inode *dir, struct dentry *dentry);
int __unionfs_d_revalidate_chain(struct dentry *dentry, struct nameidata *nd);
-int unionfs_force_rmdir(struct vfsmount *mnt, struct dentry *hidden_dentry,
int rm_parent);
+int unionfs_force_rmdir(struct vfsmount *mnt, struct dentry *hidden_dentry,
int flags);
int unionfs_force_rm(struct dentry *dentry, struct dentry **hidden_dentry, int
bindex);
int unionfs_silly_rename(struct dentry *dentry, struct dentry *hidden_dentry);
+/* Force rmv flags */
+#define FRMV_ALL 0
+#define FRMV_NOTPARENT 1
+#define FRMV_LEAF 2
+
/* The values for unionfs_interpose's flag. */
#define INTERPOSE_DEFAULT 0
#define INTERPOSE_LOOKUP 1
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs