diff options
Diffstat (limited to 'fs/logfs/gc.c')
| -rw-r--r-- | fs/logfs/gc.c | 49 |
1 files changed, 21 insertions, 28 deletions
diff --git a/fs/logfs/gc.c b/fs/logfs/gc.c index 76c242fbe1b0..caa4419285dc 100644 --- a/fs/logfs/gc.c +++ b/fs/logfs/gc.c | |||
| @@ -122,7 +122,7 @@ static void logfs_cleanse_block(struct super_block *sb, u64 ofs, u64 ino, | |||
| 122 | logfs_safe_iput(inode, cookie); | 122 | logfs_safe_iput(inode, cookie); |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | static u32 logfs_gc_segment(struct super_block *sb, u32 segno, u8 dist) | 125 | static u32 logfs_gc_segment(struct super_block *sb, u32 segno) |
| 126 | { | 126 | { |
| 127 | struct logfs_super *super = logfs_super(sb); | 127 | struct logfs_super *super = logfs_super(sb); |
| 128 | struct logfs_segment_header sh; | 128 | struct logfs_segment_header sh; |
| @@ -401,7 +401,7 @@ static int __logfs_gc_once(struct super_block *sb, struct gc_candidate *cand) | |||
| 401 | segno, (u64)segno << super->s_segshift, | 401 | segno, (u64)segno << super->s_segshift, |
| 402 | dist, no_free_segments(sb), valid, | 402 | dist, no_free_segments(sb), valid, |
| 403 | super->s_free_bytes); | 403 | super->s_free_bytes); |
| 404 | cleaned = logfs_gc_segment(sb, segno, dist); | 404 | cleaned = logfs_gc_segment(sb, segno); |
| 405 | log_gc("GC segment #%02x complete - now %x valid\n", segno, | 405 | log_gc("GC segment #%02x complete - now %x valid\n", segno, |
| 406 | valid - cleaned); | 406 | valid - cleaned); |
| 407 | BUG_ON(cleaned != valid); | 407 | BUG_ON(cleaned != valid); |
| @@ -632,38 +632,31 @@ static int check_area(struct super_block *sb, int i) | |||
| 632 | { | 632 | { |
| 633 | struct logfs_super *super = logfs_super(sb); | 633 | struct logfs_super *super = logfs_super(sb); |
| 634 | struct logfs_area *area = super->s_area[i]; | 634 | struct logfs_area *area = super->s_area[i]; |
| 635 | struct logfs_object_header oh; | 635 | gc_level_t gc_level; |
| 636 | u32 cleaned, valid, ec; | ||
| 636 | u32 segno = area->a_segno; | 637 | u32 segno = area->a_segno; |
| 637 | u32 ofs = area->a_used_bytes; | 638 | u64 ofs = dev_ofs(sb, area->a_segno, area->a_written_bytes); |
| 638 | __be32 crc; | ||
| 639 | int err; | ||
| 640 | 639 | ||
| 641 | if (!area->a_is_open) | 640 | if (!area->a_is_open) |
| 642 | return 0; | 641 | return 0; |
| 643 | 642 | ||
| 644 | for (ofs = area->a_used_bytes; | 643 | if (super->s_devops->can_write_buf(sb, ofs) == 0) |
| 645 | ofs <= super->s_segsize - sizeof(oh); | 644 | return 0; |
| 646 | ofs += (u32)be16_to_cpu(oh.len) + sizeof(oh)) { | ||
| 647 | err = wbuf_read(sb, dev_ofs(sb, segno, ofs), sizeof(oh), &oh); | ||
| 648 | if (err) | ||
| 649 | return err; | ||
| 650 | |||
| 651 | if (!memchr_inv(&oh, 0xff, sizeof(oh))) | ||
| 652 | break; | ||
| 653 | 645 | ||
| 654 | crc = logfs_crc32(&oh, sizeof(oh) - 4, 4); | 646 | printk(KERN_INFO"LogFS: Possibly incomplete write at %llx\n", ofs); |
| 655 | if (crc != oh.crc) { | 647 | /* |
| 656 | printk(KERN_INFO "interrupted header at %llx\n", | 648 | * The device cannot write back the write buffer. Most likely the |
| 657 | dev_ofs(sb, segno, ofs)); | 649 | * wbuf was already written out and the system crashed at some point |
| 658 | return 0; | 650 | * before the journal commit happened. In that case we wouldn't have |
| 659 | } | 651 | * to do anything. But if the crash happened before the wbuf was |
| 660 | } | 652 | * written out correctly, we must GC this segment. So assume the |
| 661 | if (ofs != area->a_used_bytes) { | 653 | * worst and always do the GC run. |
| 662 | printk(KERN_INFO "%x bytes unaccounted data found at %llx\n", | 654 | */ |
| 663 | ofs - area->a_used_bytes, | 655 | area->a_is_open = 0; |
| 664 | dev_ofs(sb, segno, area->a_used_bytes)); | 656 | valid = logfs_valid_bytes(sb, segno, &ec, &gc_level); |
| 665 | area->a_used_bytes = ofs; | 657 | cleaned = logfs_gc_segment(sb, segno); |
| 666 | } | 658 | if (cleaned != valid) |
| 659 | return -EIO; | ||
| 667 | return 0; | 660 | return 0; |
| 668 | } | 661 | } |
| 669 | 662 | ||
