diff options
author | James Morris <jmorris@namei.org> | 2010-05-05 20:56:07 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2010-05-05 20:56:07 -0400 |
commit | 0ffbe2699cda6afbe08501098dff8a8c2fe6ae09 (patch) | |
tree | 81b1a2305d16c873371b65c5a863c0268036cefe /fs/logfs/readwrite.c | |
parent | 4e5d6f7ec3833c0da9cf34fa5c53c6058c5908b6 (diff) | |
parent | 7ebd467551ed6ae200d7835a84bbda0dcadaa511 (diff) |
Merge branch 'master' into next
Diffstat (limited to 'fs/logfs/readwrite.c')
-rw-r--r-- | fs/logfs/readwrite.c | 76 |
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 | ||
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 | ||
@@ -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 | ||
1847 | 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) | ||
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 | } |