summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoern Engel <joern@logfs.org>2010-04-20 21:44:10 +0200
committerJoern Engel <joern@logfs.org>2010-04-20 21:44:10 +0200
commitb6349ac89eacb813f6963f7263da05bc3f483351 (patch)
tree6027a84ee332ea1598d1ac66d9345770da38d5fe
parentb8639077abf034824046ed09e779b74c4393031f (diff)
downloadop-kernel-dev-b6349ac89eacb813f6963f7263da05bc3f483351.zip
op-kernel-dev-b6349ac89eacb813f6963f7263da05bc3f483351.tar.gz
[LogFS] Split large truncated into smaller chunks
Truncate would do an almost limitless amount of work without invoking the garbage collector in between. Split it up into more manageable, though still large, chunks. Signed-off-by: Joern Engel <joern@logfs.org>
-rw-r--r--fs/logfs/readwrite.c34
1 files changed, 26 insertions, 8 deletions
diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c
index aca6c56..7e3a1e5 100644
--- a/fs/logfs/readwrite.c
+++ b/fs/logfs/readwrite.c
@@ -1837,19 +1837,37 @@ static int __logfs_truncate(struct inode *inode, u64 size)
return logfs_truncate_direct(inode, size);
}
-int logfs_truncate(struct inode *inode, u64 size)
+/*
+ * Truncate, by changing the segment file, can consume a fair amount
+ * of resources. So back off from time to time and do some GC.
+ * 8 or 2048 blocks should be well within safety limits even if
+ * every single block resided in a different segment.
+ */
+#define TRUNCATE_STEP (8 * 1024 * 1024)
+int logfs_truncate(struct inode *inode, u64 target)
{
struct super_block *sb = inode->i_sb;
- int err;
+ u64 size = i_size_read(inode);
+ int err = 0;
- logfs_get_wblocks(sb, NULL, 1);
- err = __logfs_truncate(inode, size);
- if (!err)
- err = __logfs_write_inode(inode, 0);
- logfs_put_wblocks(sb, NULL, 1);
+ size = ALIGN(size, TRUNCATE_STEP);
+ while (size > target) {
+ if (size > TRUNCATE_STEP)
+ size -= TRUNCATE_STEP;
+ else
+ size = 0;
+ if (size < target)
+ size = target;
+
+ logfs_get_wblocks(sb, NULL, 1);
+ err = __logfs_truncate(inode, target);
+ if (!err)
+ err = __logfs_write_inode(inode, 0);
+ logfs_put_wblocks(sb, NULL, 1);
+ }
if (!err)
- err = vmtruncate(inode, size);
+ err = vmtruncate(inode, target);
/* I don't trust error recovery yet. */
WARN_ON(err);
OpenPOWER on IntegriCloud