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

Reply via email to