unionfs: Cleaned up code for odf_cleanup
authorYamini Allu <yamini@louie.fsl.cs.sunysb.edu>
Sat, 16 Feb 2008 05:52:19 +0000 (00:52 -0500)
committerRachita Kothiyal <rachita@dewey.fsl.cs.sunysb.edu>
Thu, 1 May 2008 23:03:35 +0000 (19:03 -0400)
Signed-off-by: Yamini P. Allu <yamini@fsl.cs.sunysb.edu>
fs/unionfs/dirhelper.c
fs/unionfs/odf.c
fs/unionfs/odf.h
fs/unionfs/odf_internals.h
fs/unionfs/sioq.c
fs/unionfs/super.c

index 94d9441086ecc8379170a2cb8cd02f34ed8e8a0e..1c97c3e40f319e391c91044baa1e72d0365bd3ac 100644 (file)
@@ -54,18 +54,15 @@ struct unionfs_cleanup_callback {
        int err;
        int filldir_called;
        int mode;
+       int threshold;
        struct dentry *dir;
        struct vfsmount *mnt;
        struct dentry_stack *stack;
+       u64 b_to_free, i_to_free;
        u64 blocks;
        u64 inodes;
 };
 
-/* modes for cleanup_callback - what type of dir we are cleaning */
-#define CLN_IC 0   /* /odf/ic */
-#define CLN_RC 1   /* /odf/reclaim */
-#define CLN_SR 2   /* /odf/sr */
-
 /* odf_cleanup callback */
 static int cleanup_util_callback(void *dirent, const char *name, int namelen,
                                 loff_t offset, u64 ino, unsigned int d_type)
@@ -81,12 +78,16 @@ static int cleanup_util_callback(void *dirent, const char *name, int namelen,
        if (name[0] == '.' &&
            (namelen == 1 || (name[1] == '.' && namelen == 2)))
                goto out;
+       if (buf->threshold &&
+               (buf->blocks * 100 >= buf->b_to_free) &&
+               (buf->inodes * 100 >= buf->i_to_free))
+               goto out;
 
        /*
         * remove dir cache files or all if files if cleaning
         * /odf/reclaim and /odf/sr
         */
-       if ((d_type == DT_REG && buf->mode != CLN_IC) ||
+       if ((d_type == DT_REG && buf->mode != ODF_CLEAN_IC) ||
            (namelen == ODF_CONTENT_LEN &&
             !strncmp(name, ODF_CONTENT, namelen))) {
 
@@ -545,23 +546,35 @@ out:
 
 /*
  * 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.
  *
- * b_to_free and i_to_free contains the requested amount of blocks
- * and inodes to be freed MULTIPLIED BY 100
+ * @mode: The directory to be cleaned up is specified in the mode.
+ * It can be one of
+ *     ODF_CLEAN_SR:           clean /odf/sr
+ *     ODF_CLEAN_IC:           clean content files in /odf/ic
+ *     ODF_CLEAN_RECLAIM:      clean /odf/rc
+ *
+ * @b_to_free:
+ * @i_to_free:
+ * Contain pointers to unsigned values representing the requested
+ * amount of blocks and inodes to be freed MULTIPLIED BY 100.
+ * b_to_free and i_to_free can be passed NULL if the entire directory
+ * is to be cleaned.  In case the number of blocks to be freed or
+ * inodes to be freed is specified, the cleanup routine tries to
+ * cleanup only as many blocks/inodes.
+ *
+ * Return Value:
+ *
+ * 0     - If it manages to bring inodes/block below requested
+ * threshold or successfully deletes the contents of a directory.
  *
- * Flags :
- *     ODF_CLEAN_DEFAULT: clean all caches but /odf/sr
- *     ODF_CLEAN_SR: clean /odf/sr
- *     ODF_CLEAN_FULL: clean /odf/ic and /odf/reclaim ignoring
- thresholds
- * Returns 1 if it manages to bring inodes/block below requested,
- * threshold and 0 if not.
+ * ENOSPC - If the function fails to bring blocks/inodes below threshold.
+ * b_to_free and i_to_free will point to values representing the
+ * blocks/inodes that are yet to be freed to bring them below threshold.
+ *
+ * A corresponding error code in case of any other error.
  */
-int odf_cleanup(struct odf_sb_info *odf, int mode, u64 b_to_free,
-               u64 i_to_free)
+int odf_cleanup(struct odf_sb_info *odf, int mode, u64 *b_to_free,
+               u64 *i_to_free)
 {
        int err = 0;
        struct file *file;
@@ -584,16 +597,32 @@ int odf_cleanup(struct odf_sb_info *odf, int mode, u64 b_to_free,
        }
        buf->err = 0;
        buf->mnt = odf->path.mnt;
-       buf->mode = CLN_IC;
+       buf->mode = mode;
+       buf->threshold = 0;
        buf->blocks = 0;
        buf->inodes = 0;
        buf->stack = &stack;
+       if (b_to_free != NULL) {
+               buf->b_to_free = *b_to_free;
+               buf->threshold = 1;
+       }
+       if (i_to_free != NULL) {
+               buf->i_to_free = *i_to_free;
+               buf->threshold = 1;
+       }
+       if (mode == ODF_CLEAN_SR) {
+               dget(odf->sr);
+               stack.item[stack.n++] = odf->sr;
+       }
+       if (mode == ODF_CLEAN_IC) {
+               dget(odf->ic);
+               stack.item[stack.n++] = odf->ic;
+       }
+       if (mode == ODF_CLEAN_RECLAIM) {
+               dget(odf->rc);
+               stack.item[stack.n++] = odf->rc;
+       }
 
-       /* first cleanup odf/ic */
-       dget(odf->ic);
-       stack.item[stack.n++] = odf->ic;
-
-cleanup_loop:
        /*
         * The cleanup loop pops a dentry off the stack, reads all
         * its entries, unlinking dir cache files and files in
@@ -606,7 +635,7 @@ cleanup_loop:
                 * we need to dget /odf/reclaim and /odf/sr dirs again since
                 * we need them after we close the file
                 */
-               if (buf->mode != CLN_IC)
+               if (buf->mode != ODF_CLEAN_IC)
                        dget(dentry);
                mntget(odf->path.mnt);
 
@@ -621,75 +650,65 @@ cleanup_loop:
                do {
                        buf->filldir_called = 0;
                        err = vfs_readdir(file, cleanup_util_callback, buf);
+                       if (err < 0) {
+                               fput(file);
+                               goto check;
+                       }
                        if (buf->err)
                                err = buf->err;
                } while ((err >= 0) && buf->filldir_called);
-               fput(file);
 
-               if (!err && buf->mode != CLN_IC) {
-                       /*
-                        * remove all directories in odf/reclaim or odf/sr
-                        * This assumes that the odf/reclaim dir structure
-                        * is entirely flat, ie only odf/reclaim contains
-                        * subdirectories
-                        */
-                       if (dentry != odf->rc && dentry != odf->sr) {
-                               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);
+               fput(file);
+               if (err < 0)
+                       goto check;
+               if (buf->mode == ODF_CLEAN_IC)
+                       goto check;
+               /*
+                * remove all directories in odf/reclaim or odf/sr
+                * This assumes that the odf/reclaim dir structure
+                * is entirely flat, ie only odf/reclaim contains
+                * subdirectories
+                */
+               if (dentry != odf->rc && dentry != odf->sr) {
+                       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--;
                        }
-                       dput(dentry);
+                       buf->blocks += blocks + 1;
+                       buf->inodes++;
+                       err = vfs_rmdir(dentry->d_parent->d_inode,
+                                       dentry);
+                       BUG_ON(err == -ENOTEMPTY);
                }
+               dput(dentry);
 
+check:
                /* check if we have reached the threshold */
-               if ((mode & ODF_CLEAN_DEFAULT) &&
-                   (buf->blocks * 100 >= b_to_free) &&
-                   (buf->inodes * 100 >= i_to_free))
+               if ((buf->threshold == 1) &&
+                   (buf->blocks * 100 >= *b_to_free) &&
+                   (buf->inodes * 100 >= *i_to_free))
                        success = 1;
        }
 
-       if (err < 0)
-               goto out;
-
-       if (!success && ((mode & ODF_CLEAN_DEFAULT) ||
-                        (mode & ODF_CLEAN_FULL))) {
-               BUG_ON(stack.n);
-
-               /* if we did not succeed, clean up odf/reclaim as well */
-               if (buf->mode == CLN_IC) {
-                       buf->mode = CLN_RC;
-                       dget(odf->rc);
-                       stack.item[stack.n++] = odf->rc;
-                       goto cleanup_loop;
-               }
-       }
-
-       /* cleanup /odf/sr */
-       if ((mode & ODF_CLEAN_SR) && (buf->mode != CLN_SR)) {
-               buf->mode = CLN_SR;
-               dget(odf->sr);
-               stack.item[stack.n++] = odf->sr;
-               goto cleanup_loop;
-       }
-
-       if (mode & ODF_CLEAN_DEFAULT)
-               err = success;
-       else
-               err = 1;
 out:
        BUG_ON(stack.n < 0);
        while (stack.n)
                dput(__odf_dstack_pop(&stack));
-
+       if (success)
+               err = 0;
+       else if (!success && buf->threshold) {
+               if (buf->b_to_free > (buf->blocks * 100)) {
+                       *b_to_free = buf->b_to_free - (buf->blocks * 100);
+                       err = -ENOSPC;
+               }
+               if (buf->i_to_free > (buf->inodes * 100)) {
+                       *i_to_free = buf->i_to_free - (buf->inodes * 100);
+                       err = -ENOSPC;
+               }
+       }
        kfree(buf);
        kfree(stack.item);
        return err;
index c161ec8b193282640c68c5ee6bcdd3a1d7126826..5989670512ef40f3e6c1904430c0002b161ec4b3 100644 (file)
@@ -208,7 +208,7 @@ int odf_read_super(struct super_block *sb, char *data)
        sioa->cleanup.attr = get_attributes();
        sioa->cleanup.flags = ((options & ODF_OPT_KEEPCACHE) ?
                               ODF_CLEAN_DEFAULT :
-                              ODF_CLEAN_SR|ODF_CLEAN_FULL);
+                              ODF_CLEAN_SR|ODF_CLEAN_IC|ODF_CLEAN_RECLAIM);
        osi->cleanup = sioa;
        osi->path.mnt = nd.mnt;
        osi->path.dentry = nd.dentry;
@@ -2063,10 +2063,27 @@ void __odf_cleanup(void *args)
        sioa_args->timeout = msecs_to_jiffies(cl->attr->timeout->val * 1000);
 
        /* FIXME: LOCK need to lock ic/reclaim/sr? */
+       if (cl->flags & ODF_CLEAN_SR) {
+               err = odf_cleanup(cl->odf, ODF_CLEAN_SR, NULL, NULL);
+               if (err < 0)
+                       printk(KERN_WARNING
+                               "unionfs: cleanup thread: error %d\n", err);
+       }
+       if ((cl->flags & ODF_CLEAN_IC) && (cl->flags & ODF_CLEAN_RECLAIM)) {
+               err = odf_cleanup(cl->odf, ODF_CLEAN_IC, NULL, NULL);
+               if (err < 0)
+                       printk(KERN_WARNING
+                               "unionfs: cleanup thread: error %d\n", err);
+               err = odf_cleanup(cl->odf, ODF_CLEAN_RECLAIM, NULL, NULL);
+               if (err < 0)
+                       printk(KERN_WARNING
+                               "unionfs: cleanup thread: error %d\n", err);
+       }
 
-       vfs_statfs(cl->odf->sb, &stat);
        if (cl->flags & ODF_CLEAN_DEFAULT) {
-
+               err = vfs_statfs(cl->odf->sb, &stat);
+               if (err)
+                       goto out;
                /* check if blocks is above threshold */
                if (stat.f_bavail * 100 < stat.f_blocks
                    * (100 - cl->attr->thresh_b_high->val)) {
@@ -2084,18 +2101,23 @@ void __odf_cleanup(void *args)
                                (100 - cl->attr->thresh_i_low->val) -
                                (stat.f_ffree * 100);
                }
+               if (cleanup) {
+                       err = odf_cleanup(cl->odf, ODF_CLEAN_IC,
+                                       &b_size, &i_size);
+                       if (!err)
+                               goto out;
+                       if (err == -ENOSPC)
+                               err = odf_cleanup(cl->odf, ODF_CLEAN_RECLAIM,
+                                               &b_size, &i_size);
+                       if (err == -ENOSPC)
+                               printk(KERN_WARNING "unionfs: cleanup "
+                               "failed to bring odf below threshold\n");
+                       else if (err < 0)
+                               printk(KERN_WARNING "unionfs: cleanup thread: "
+                                                  "error %d\n", err);
+               }
        }
-
-       if (cl->flags & ODF_CLEAN_FULL || cl->flags & ODF_CLEAN_SR)
-               cleanup = 1;
-
-       if (cleanup)
-               err = odf_cleanup(cl->odf, cl->flags, b_size, i_size);
-       if (err < 0)
-               printk(KERN_WARNING "unionfs: cleanup thread: error %d\n", err);
-       else if (err == 0 && cl->success == 1)
-               printk(KERN_WARNING "unionfs: cleanup failed to bring odf "
-                      "below threshold\n");
+out:
        cl->success = err;
        cl->flags = ODF_CLEAN_DEFAULT;
 }
index 0ffba5694400ebe30db46cfcf46362c4e31fec7d..e8b8def7d3cabb11bc39dd564592cdc739de454e 100644 (file)
@@ -28,8 +28,8 @@
 /* cleanup thread flags */
 #define ODF_CLEAN_DEFAULT      0x01
 #define ODF_CLEAN_SR           0x02
-#define ODF_CLEAN_FULL         0x04
-
+#define ODF_CLEAN_IC           0x04
+#define ODF_CLEAN_RECLAIM      0x08
 #define ODF_CONTENT "content"   /* name of cached dirs file in /odf/ic */
 #define ODF_CONTENT_LEN (sizeof(ODF_CONTENT) - 1)
 
index 77442ca6f0ab875e6170a9639004094ae0e6b5fd..05872505d3d83cd3898d926af0aee2ef4b25feb6 100644 (file)
@@ -57,8 +57,8 @@ static inline int __odf_is_wh(struct odf_sb_info *osi, struct dentry *dentry)
 int odf_set_opaque(struct dentry *odf_dentry, int branch);
 
 /* cleanup thread functions */
-int odf_cleanup(struct odf_sb_info *odf, int mode, u64 b_to_free,
-               u64 i_to_free);
+int odf_cleanup(struct odf_sb_info *odf, int mode, u64 *b_to_free,
+               u64 *i_to_free);
 
 extern void generate_random_uuid(unsigned char uuid_out[16]);
 
index e9ff242e56bdbfd4ee2034057243534d7c904314..5c2c7df03f7dc5eb63ace76af722383b591945f6 100644 (file)
@@ -32,7 +32,6 @@ int __init init_sioq(void)
                return 0;
 
        err = PTR_ERR(superio_workqueue);
-       printk(KERN_ERR "unionfs: create_workqueue failed %d\n", err);
        superio_workqueue = NULL;
        return err;
 }
index cb2618f6a14e4f65677aa5915bb0dcfb4dbbd433..965d301a5105f86933cd25e8331c57525772f4eb 100644 (file)
@@ -732,7 +732,7 @@ out_no_change:
         * it to cleanup everything
         */
        if (!odf_keepcache) {
-               odf->cleanup->cleanup.flags = ODF_CLEAN_FULL;
+               odf->cleanup->cleanup.flags = ODF_CLEAN_IC | ODF_CLEAN_RECLAIM;
                wake_up_and_wait_sioa(odf->cleanup);
        }