aboutsummaryrefslogtreecommitdiffstats
path: root/fs/logfs/readwrite.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/logfs/readwrite.c')
-rw-r--r--fs/logfs/readwrite.c76
1 files changed, 43 insertions, 33 deletions
diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c
index c3a3a6814b84..3159db6958e5 100644
--- a/fs/logfs/readwrite.c
+++ b/fs/logfs/readwrite.c
@@ -18,6 +18,7 @@
18 */ 18 */
19#include "logfs.h" 19#include "logfs.h"
20#include <linux/sched.h> 20#include <linux/sched.h>
21#include <linux/slab.h>
21 22
22static u64 adjust_bix(u64 bix, level_t level) 23static u64 adjust_bix(u64 bix, level_t level)
23{ 24{
@@ -429,25 +430,6 @@ static void inode_write_block(struct logfs_block *block)
429 } 430 }
430} 431}
431 432
432static gc_level_t inode_block_level(struct logfs_block *block)
433{
434 BUG_ON(block->inode->i_ino == LOGFS_INO_MASTER);
435 return GC_LEVEL(LOGFS_MAX_LEVELS);
436}
437
438static gc_level_t indirect_block_level(struct logfs_block *block)
439{
440 struct page *page;
441 struct inode *inode;
442 u64 bix;
443 level_t level;
444
445 page = block->page;
446 inode = page->mapping->host;
447 logfs_unpack_index(page->index, &bix, &level);
448 return expand_level(inode->i_ino, level);
449}
450
451/* 433/*
452 * This silences a false, yet annoying gcc warning. I hate it when my editor 434 * This silences a false, yet annoying gcc warning. I hate it when my editor
453 * jumps into bitops.h each time I recompile this file. 435 * jumps into bitops.h each time I recompile this file.
@@ -586,14 +568,12 @@ static void indirect_free_block(struct super_block *sb,
586 568
587static struct logfs_block_ops inode_block_ops = { 569static struct logfs_block_ops inode_block_ops = {
588 .write_block = inode_write_block, 570 .write_block = inode_write_block,
589 .block_level = inode_block_level,
590 .free_block = inode_free_block, 571 .free_block = inode_free_block,
591 .write_alias = inode_write_alias, 572 .write_alias = inode_write_alias,
592}; 573};
593 574
594struct logfs_block_ops indirect_block_ops = { 575struct logfs_block_ops indirect_block_ops = {
595 .write_block = indirect_write_block, 576 .write_block = indirect_write_block,
596 .block_level = indirect_block_level,
597 .free_block = indirect_free_block, 577 .free_block = indirect_free_block,
598 .write_alias = indirect_write_alias, 578 .write_alias = indirect_write_alias,
599}; 579};
@@ -1240,6 +1220,18 @@ static void free_shadow(struct inode *inode, struct logfs_shadow *shadow)
1240 mempool_free(shadow, super->s_shadow_pool); 1220 mempool_free(shadow, super->s_shadow_pool);
1241} 1221}
1242 1222
1223static void mark_segment(struct shadow_tree *tree, u32 segno)
1224{
1225 int err;
1226
1227 if (!btree_lookup32(&tree->segment_map, segno)) {
1228 err = btree_insert32(&tree->segment_map, segno, (void *)1,
1229 GFP_NOFS);
1230 BUG_ON(err);
1231 tree->no_shadowed_segments++;
1232 }
1233}
1234
1243/** 1235/**
1244 * fill_shadow_tree - Propagate shadow tree changes due to a write 1236 * fill_shadow_tree - Propagate shadow tree changes due to a write
1245 * @inode: Inode owning the page 1237 * @inode: Inode owning the page
@@ -1287,6 +1279,8 @@ static void fill_shadow_tree(struct inode *inode, struct page *page,
1287 1279
1288 super->s_dirty_used_bytes += shadow->new_len; 1280 super->s_dirty_used_bytes += shadow->new_len;
1289 super->s_dirty_free_bytes += shadow->old_len; 1281 super->s_dirty_free_bytes += shadow->old_len;
1282 mark_segment(tree, shadow->old_ofs >> super->s_segshift);
1283 mark_segment(tree, shadow->new_ofs >> super->s_segshift);
1290 } 1284 }
1291} 1285}
1292 1286
@@ -1844,19 +1838,37 @@ static int __logfs_truncate(struct inode *inode, u64 size)
1844 return logfs_truncate_direct(inode, size); 1838 return logfs_truncate_direct(inode, size);
1845} 1839}
1846 1840
1847int logfs_truncate(struct inode *inode, u64 size) 1841/*
1842 * Truncate, by changing the segment file, can consume a fair amount
1843 * of resources. So back off from time to time and do some GC.
1844 * 8 or 2048 blocks should be well within safety limits even if
1845 * every single block resided in a different segment.
1846 */
1847#define TRUNCATE_STEP (8 * 1024 * 1024)
1848int logfs_truncate(struct inode *inode, u64 target)
1848{ 1849{
1849 struct super_block *sb = inode->i_sb; 1850 struct super_block *sb = inode->i_sb;
1850 int err; 1851 u64 size = i_size_read(inode);
1852 int err = 0;
1851 1853
1852 logfs_get_wblocks(sb, NULL, 1); 1854 size = ALIGN(size, TRUNCATE_STEP);
1853 err = __logfs_truncate(inode, size); 1855 while (size > target) {
1854 if (!err) 1856 if (size > TRUNCATE_STEP)
1855 err = __logfs_write_inode(inode, 0); 1857 size -= TRUNCATE_STEP;
1856 logfs_put_wblocks(sb, NULL, 1); 1858 else
1859 size = 0;
1860 if (size < target)
1861 size = target;
1862
1863 logfs_get_wblocks(sb, NULL, 1);
1864 err = __logfs_truncate(inode, target);
1865 if (!err)
1866 err = __logfs_write_inode(inode, 0);
1867 logfs_put_wblocks(sb, NULL, 1);
1868 }
1857 1869
1858 if (!err) 1870 if (!err)
1859 err = vmtruncate(inode, size); 1871 err = vmtruncate(inode, target);
1860 1872
1861 /* I don't trust error recovery yet. */ 1873 /* I don't trust error recovery yet. */
1862 WARN_ON(err); 1874 WARN_ON(err);
@@ -2250,8 +2262,6 @@ void logfs_cleanup_rw(struct super_block *sb)
2250 struct logfs_super *super = logfs_super(sb); 2262 struct logfs_super *super = logfs_super(sb);
2251 2263
2252 destroy_meta_inode(super->s_segfile_inode); 2264 destroy_meta_inode(super->s_segfile_inode);
2253 if (super->s_block_pool) 2265 logfs_mempool_destroy(super->s_block_pool);
2254 mempool_destroy(super->s_block_pool); 2266 logfs_mempool_destroy(super->s_shadow_pool);
2255 if (super->s_shadow_pool)
2256 mempool_destroy(super->s_shadow_pool);
2257} 2267}