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)
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))) {
/*
* 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;
}
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
* 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);
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;
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;
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)) {
(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;
}