From: Yamini Allu Date: Sat, 16 Feb 2008 05:52:19 +0000 (-0500) Subject: unionfs: Cleaned up code for odf_cleanup X-Git-Url: https://git.fsl.cs.sunysb.edu/?a=commitdiff_plain;h=2962761599b8546605b6586296c4d18ca96815a9;p=unionfs-odf.git unionfs: Cleaned up code for odf_cleanup Signed-off-by: Yamini P. Allu --- diff --git a/fs/unionfs/dirhelper.c b/fs/unionfs/dirhelper.c index 94d9441086..1c97c3e40f 100644 --- a/fs/unionfs/dirhelper.c +++ b/fs/unionfs/dirhelper.c @@ -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; diff --git a/fs/unionfs/odf.c b/fs/unionfs/odf.c index c161ec8b19..5989670512 100644 --- a/fs/unionfs/odf.c +++ b/fs/unionfs/odf.c @@ -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; } diff --git a/fs/unionfs/odf.h b/fs/unionfs/odf.h index 0ffba56944..e8b8def7d3 100644 --- a/fs/unionfs/odf.h +++ b/fs/unionfs/odf.h @@ -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) diff --git a/fs/unionfs/odf_internals.h b/fs/unionfs/odf_internals.h index 77442ca6f0..05872505d3 100644 --- a/fs/unionfs/odf_internals.h +++ b/fs/unionfs/odf_internals.h @@ -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]); diff --git a/fs/unionfs/sioq.c b/fs/unionfs/sioq.c index e9ff242e56..5c2c7df03f 100644 --- a/fs/unionfs/sioq.c +++ b/fs/unionfs/sioq.c @@ -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; } diff --git a/fs/unionfs/super.c b/fs/unionfs/super.c index cb2618f6a1..965d301a51 100644 --- a/fs/unionfs/super.c +++ b/fs/unionfs/super.c @@ -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); }