commit c70c2e0af732948b1ee2b4ca472daa55ade65139
Author: Yiannis Pericleous <[EMAIL PROTECTED]>
Date:   Mon Apr 2 16:24:33 2007 -0400

    non-recursive cleanup, and stop cleaning if threshold is reached

diff --git a/fs/unionfs/dirhelper.c b/fs/unionfs/dirhelper.c
index e84b699..3d0bdfb 100644
--- a/fs/unionfs/dirhelper.c
+++ b/fs/unionfs/dirhelper.c
@@ -55,6 +55,7 @@ struct unionfs_rdutil_callback {
        struct unionfs_dir_state *rdstate;
        int mode;
 };
+
 struct unionfs_rmdir_callback {
        int err;
        int filldir_called;
@@ -63,6 +64,19 @@ struct unionfs_rmdir_callback {
        int isleaf;
        int mode;
 };
+
+/* callback structure for odf_cleanup*/
+struct unionfs_cleanup_callback {
+       int err;
+       int filldir_called;
+       int reclaim;
+       struct dentry *dir;
+       struct vfsmount *mnt;
+       struct dentry_stack *stack;
+       u64 blocks;
+       u64 inodes;
+};
+
 static int rmdir_util_callback(void *dirent, const char *name, int namelen,
                                 loff_t offset, u64 ino, unsigned int d_type)
 {
@@ -997,3 +1011,147 @@ out:
                kfree(buf);
        return err;
 }
+
+/*
+ * Cleanup function for the odf cleanup thread.
+ * First cleans up the dir caches in odf/ic and then everything
+ * in odf/reclaim. It stops once the requested blocks/inodes
+ * were freed. 
+ * size contains the requested amount of inodes/blocks to be freed
+ * MULTIPLIED BY 100
+ * Modes : 
+ *     ODF_CLEAN_ALL: cleans all the dir caches and odf/reclaim
+ *     ODF_CLEAN_CACHE: cleans all the dir caches
+ *     ODF_CLEAN_BLOCKS: clean until size blocks are freed
+ *     ODF_CLEAN_INODES: clean until size inodes are freed
+ */
+int odf_cleanup(struct odf_sb_info *odf, int mode, u64 size)
+{
+       int err = 0;
+       struct file *file;
+       struct unionfs_cleanup_callback *buf = NULL;
+       struct dentry *dentry;
+       struct dentry_stack stack;
+       int success = 0, reclaim = 0;
+       loff_t bytes, isize;
+       int blocks;
+
+       stack.size = STACK_SIZE;
+       stack.n = 0;
+       stack.item = kmalloc(stack.size * sizeof(struct dentry *), GFP_KERNEL);
+       if (!stack.item) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       buf = kmalloc(sizeof(struct unionfs_cleanup_callback), GFP_KERNEL);
+       if (!buf) {
+               err = -ENOMEM;
+               goto out;
+       }
+       buf->err = 0;
+       buf->mnt = odf->mnt;
+       buf->reclaim = reclaim;
+       buf->blocks = 0;
+       buf->inodes = 0;
+       buf->stack = &stack;
+
+       /* first cleanup odf/ic */
+       dget(odf->odi_ic->dentry);
+       stack.item[stack.n++] = odf->odi_ic->dentry;
+
+
+cleanup_loop:
+       /* The cleanup loop pops a dentry off the stack, reads all
+        * its entries, unlinking dir cache files and files in 
+        * odf/reclaim and pushing to the stack all directories
+        */
+       while (err >= 0 && stack.n > 0 && !success) {
+               dentry = stack.item[--stack.n]; /* pop */
+               
+               /* we need to dget /reclaim dirs again since we need
+                * them after we close the file 
+                */
+               if (reclaim)
+                       dget(dentry);
+               mntget(odf->mnt);
+
+               file = dentry_open(dentry, odf->mnt, O_RDONLY);
+               if (IS_ERR(file)) {
+                       err = PTR_ERR(file);
+                       dput(dentry);
+                       goto out;
+               }
+
+               buf->dir = dentry;
+               do {
+                       buf->filldir_called = 0;
+                       err = vfs_readdir(file, cleanup_util_callback, buf);
+                       if (buf->err)
+                               err = buf->err;
+               } while ((err >= 0) && buf->filldir_called);
+               fput(file);
+
+               if (!err && reclaim) {
+                       /* remove all directories in odf/reclaim
+                        * This assumes that the odf/reclaim dir structure
+                        * is entirely flat, ie only odf/reclaim contains
+                        * subdirectories 
+                        */
+                       if (dentry != odf->odi_rc->dentry) {
+                               blocks = dentry->d_inode->i_blocks;
+                               bytes = blocks * dentry->d_sb->s_blocksize;
+                               isize = i_size_read(dentry->d_inode);
+                               while (bytes > isize) {
+                                       bytes -= dentry->d_sb->s_blocksize;
+                                       blocks--;
+                               }
+                               buf->blocks += blocks + 1;
+                               buf->inodes++;
+                               err = vfs_rmdir(dentry->d_parent->d_inode, 
dentry);
+                               BUG_ON(err == -ENOTEMPTY);
+                       }
+                       dput(dentry);
+               }
+       
+               /* check if we have reached the threshold */    
+               if (mode == ODF_CLEAN_BLOCKS && buf->blocks * 100 >= size)
+                       success = 1;
+               else if (mode == ODF_CLEAN_INODES && buf->inodes * 100 >= size)
+                       success = 1;
+       }
+
+       if (err < 0)
+               goto out;
+       
+       if (mode == ODF_CLEAN_CACHE)
+               success = 1;    
+
+       if (!success) {
+               BUG_ON(stack.n);
+               
+               /* if we did not succeed, clean up odf/reclaim as well */
+               if (!reclaim) {
+                       reclaim = 1;
+                       buf->reclaim = 1;
+                       dget(odf->odi_rc->dentry);
+                       stack.item[stack.n++] = odf->odi_rc->dentry;
+                       goto cleanup_loop;
+               }
+               else if (mode == ODF_CLEAN_BLOCKS)
+                       printk("unionfs: Failed to bring free odf data blocks 
below threshold\n");
+               else if (mode == ODF_CLEAN_INODES)
+                       printk("unionfs: Failed to bring free odf inodes below 
threshold\n");
+       }
+       
+
+out:
+       BUG_ON(stack.n < 0);
+       while(stack.n)
+               dput(stack.item[--stack.n]);
+       
+       kfree(buf);
+       kfree(stack.item);
+       return err;
+}
+
diff --git a/fs/unionfs/odf.h b/fs/unionfs/odf.h
index 4976eb3..36669bc 100644
--- a/fs/unionfs/odf.h
+++ b/fs/unionfs/odf.h
@@ -68,6 +68,11 @@
 #define ODF_CONTENT "content"
 #define ODF_CONTENT_LEN 7
 
+#define ODF_CLEAN_ALL 1
+#define ODF_CLEAN_CACHE 2
+#define ODF_CLEAN_INODES 3
+#define ODF_CLEAN_BLOCKS 4
+
 /* super */
 struct odf_sb_info* odf_read_super(char *options);
 void odf_put_super(struct odf_sb_info *osi);
@@ -165,6 +170,7 @@ extern void generate_random_uuid(unsigned char 
uuid_out[16]);
 
 /* cleanup thread functions */
 extern void __odf_cleanup(void *args);
+int odf_cleanup(struct odf_sb_info *odf, int mode, u64 size);
 
 /* Macros for locking an odf dentry info. */
 static inline void odf_lock(struct odf_dentry_info *odi)
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs

Reply via email to