aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChao Yu <yuchao0@huawei.com>2019-05-16 20:40:43 +0800
committerJaegeuk Kim <jaegeuk@kernel.org>2019-05-20 17:42:52 -0700
commit54244dcafddcf87355b5515b60ea084ddb47e2d0 (patch)
tree7496024a7cf9fa82471d3fc0eedcbb28a78504ac
parent9e0a58749de8b62932388cfb645ee6248cd1b413 (diff)
downloadf2fs-tools-54244dcafddcf87355b5515b60ea084ddb47e2d0.tar.gz
fsck.f2fs: update curseg .next_blkoff/.alloc_type preferential
If .next_blkoff is inconsistent, we can update curseg .next_blkoff to first unused block address, and change .alloc_type to SSR preferential, instead of move curseg to other position. This can help to repair fuzzed image which has no more free segment. Signed-off-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r--fsck/fsck.c23
-rw-r--r--fsck/fsck.h1
-rw-r--r--fsck/mount.c31
3 files changed, 50 insertions, 5 deletions
diff --git a/fsck/fsck.c b/fsck/fsck.c
index 247b75e..6f0f262 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -2164,6 +2164,23 @@ int check_curseg_offsets(struct f2fs_sb_info *sbi)
return 0;
}
+static void fix_curseg_info(struct f2fs_sb_info *sbi)
+{
+ int i, need_update = 0;
+
+ for (i = 0; i < NO_CHECK_TYPE; i++) {
+ if (check_curseg_offset(sbi, i)) {
+ update_curseg_info(sbi, i);
+ need_update = 1;
+ }
+ }
+
+ if (need_update) {
+ write_curseg_info(sbi);
+ flush_curseg_sit_entries(sbi);
+ }
+}
+
int check_sit_types(struct f2fs_sb_info *sbi)
{
unsigned int i;
@@ -2752,11 +2769,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
fix_hard_links(sbi);
fix_nat_entries(sbi);
rewrite_sit_area_bitmap(sbi);
- if (check_curseg_offsets(sbi)) {
- move_curseg_info(sbi, SM_I(sbi)->main_blkaddr, 0);
- write_curseg_info(sbi);
- flush_curseg_sit_entries(sbi);
- }
+ fix_curseg_info(sbi);
fix_checksum(sbi);
fix_checkpoint(sbi);
} else if (is_set_ckpt_flags(cp, CP_FSCK_FLAG) ||
diff --git a/fsck/fsck.h b/fsck/fsck.h
index c56e733..f00036e 100644
--- a/fsck/fsck.h
+++ b/fsck/fsck.h
@@ -185,6 +185,7 @@ extern void f2fs_do_umount(struct f2fs_sb_info *);
extern int f2fs_sparse_initialize_meta(struct f2fs_sb_info *);
extern void flush_journal_entries(struct f2fs_sb_info *);
+extern void update_curseg_info(struct f2fs_sb_info *, int);
extern void zero_journal_entries(struct f2fs_sb_info *);
extern void flush_sit_entries(struct f2fs_sb_info *);
extern void move_curseg_info(struct f2fs_sb_info *, u64, int);
diff --git a/fsck/mount.c b/fsck/mount.c
index 21d71d4..aecd0cd 100644
--- a/fsck/mount.c
+++ b/fsck/mount.c
@@ -2159,6 +2159,30 @@ void flush_sit_entries(struct f2fs_sb_info *sbi)
free(sit_blk);
}
+int relocate_curseg_offset(struct f2fs_sb_info *sbi, int type)
+{
+ struct curseg_info *curseg = CURSEG_I(sbi, type);
+ struct seg_entry *se = get_seg_entry(sbi, curseg->segno);
+ unsigned int i;
+
+ for (i = 0; i < sbi->blocks_per_seg; i++) {
+ if (!f2fs_test_bit(i, (const char *)se->cur_valid_map))
+ break;
+ }
+
+ if (i == sbi->blocks_per_seg)
+ return -EINVAL;
+
+ DBG(1, "Update curseg[%d].next_blkoff %u -> %u, alloc_type %s -> SSR\n",
+ type, curseg->next_blkoff, i,
+ curseg->alloc_type == LFS ? "LFS" : "SSR");
+
+ curseg->next_blkoff = i;
+ curseg->alloc_type = SSR;
+
+ return 0;
+}
+
int find_next_free_block(struct f2fs_sb_info *sbi, u64 *to, int left, int type)
{
struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
@@ -2255,6 +2279,13 @@ void move_curseg_info(struct f2fs_sb_info *sbi, u64 from, int left)
}
}
+void update_curseg_info(struct f2fs_sb_info *sbi, int type)
+{
+ if (!relocate_curseg_offset(sbi, type))
+ return;
+ move_curseg_info(sbi, SM_I(sbi)->main_blkaddr, 0);
+}
+
void zero_journal_entries(struct f2fs_sb_info *sbi)
{
int i;