diff options
Diffstat (limited to 'fs/logfs/readwrite.c')
-rw-r--r-- | fs/logfs/readwrite.c | 89 |
1 files changed, 55 insertions, 34 deletions
diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c index 7a23b3e7c0a7..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 | ||
22 | static u64 adjust_bix(u64 bix, level_t level) | 23 | static 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 | ||
432 | static 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 | |||
438 | static 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 | ||
587 | static struct logfs_block_ops inode_block_ops = { | 569 | static 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 | ||
594 | struct logfs_block_ops indirect_block_ops = { | 575 | struct 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 | ||
1223 | static 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 | ||
@@ -1594,7 +1588,6 @@ int logfs_delete(struct inode *inode, pgoff_t index, | |||
1594 | return ret; | 1588 | return ret; |
1595 | } | 1589 | } |
1596 | 1590 | ||
1597 | /* Rewrite cannot mark the inode dirty but has to write it immediatly. */ | ||
1598 | int logfs_rewrite_block(struct inode *inode, u64 bix, u64 ofs, | 1591 | int logfs_rewrite_block(struct inode *inode, u64 bix, u64 ofs, |
1599 | gc_level_t gc_level, long flags) | 1592 | gc_level_t gc_level, long flags) |
1600 | { | 1593 | { |
@@ -1611,6 +1604,18 @@ int logfs_rewrite_block(struct inode *inode, u64 bix, u64 ofs, | |||
1611 | if (level != 0) | 1604 | if (level != 0) |
1612 | alloc_indirect_block(inode, page, 0); | 1605 | alloc_indirect_block(inode, page, 0); |
1613 | err = logfs_write_buf(inode, page, flags); | 1606 | err = logfs_write_buf(inode, page, flags); |
1607 | if (!err && shrink_level(gc_level) == 0) { | ||
1608 | /* Rewrite cannot mark the inode dirty but has to | ||
1609 | * write it immediatly. | ||
1610 | * Q: Can't we just create an alias for the inode | ||
1611 | * instead? And if not, why not? | ||
1612 | */ | ||
1613 | if (inode->i_ino == LOGFS_INO_MASTER) | ||
1614 | logfs_write_anchor(inode->i_sb); | ||
1615 | else { | ||
1616 | err = __logfs_write_inode(inode, flags); | ||
1617 | } | ||
1618 | } | ||
1614 | } | 1619 | } |
1615 | logfs_put_write_page(page); | 1620 | logfs_put_write_page(page); |
1616 | return err; | 1621 | return err; |
@@ -1833,19 +1838,37 @@ static int __logfs_truncate(struct inode *inode, u64 size) | |||
1833 | return logfs_truncate_direct(inode, size); | 1838 | return logfs_truncate_direct(inode, size); |
1834 | } | 1839 | } |
1835 | 1840 | ||
1836 | int 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) | ||
1848 | int logfs_truncate(struct inode *inode, u64 target) | ||
1837 | { | 1849 | { |
1838 | struct super_block *sb = inode->i_sb; | 1850 | struct super_block *sb = inode->i_sb; |
1839 | int err; | 1851 | u64 size = i_size_read(inode); |
1852 | int err = 0; | ||
1840 | 1853 | ||
1841 | logfs_get_wblocks(sb, NULL, 1); | 1854 | size = ALIGN(size, TRUNCATE_STEP); |
1842 | err = __logfs_truncate(inode, size); | 1855 | while (size > target) { |
1843 | if (!err) | 1856 | if (size > TRUNCATE_STEP) |
1844 | err = __logfs_write_inode(inode, 0); | 1857 | size -= TRUNCATE_STEP; |
1845 | 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 | } | ||
1846 | 1869 | ||
1847 | if (!err) | 1870 | if (!err) |
1848 | err = vmtruncate(inode, size); | 1871 | err = vmtruncate(inode, target); |
1849 | 1872 | ||
1850 | /* I don't trust error recovery yet. */ | 1873 | /* I don't trust error recovery yet. */ |
1851 | WARN_ON(err); | 1874 | WARN_ON(err); |
@@ -2239,8 +2262,6 @@ void logfs_cleanup_rw(struct super_block *sb) | |||
2239 | struct logfs_super *super = logfs_super(sb); | 2262 | struct logfs_super *super = logfs_super(sb); |
2240 | 2263 | ||
2241 | destroy_meta_inode(super->s_segfile_inode); | 2264 | destroy_meta_inode(super->s_segfile_inode); |
2242 | if (super->s_block_pool) | 2265 | logfs_mempool_destroy(super->s_block_pool); |
2243 | mempool_destroy(super->s_block_pool); | 2266 | logfs_mempool_destroy(super->s_shadow_pool); |
2244 | if (super->s_shadow_pool) | ||
2245 | mempool_destroy(super->s_shadow_pool); | ||
2246 | } | 2267 | } |