aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk@kernel.org>2015-12-09 20:30:41 -0800
committerGreg Wallace <greg@gregtwallace.com>2016-01-19 22:02:20 -0500
commitd19dbfc9a6617d1644f21272354daeb16f064bf5 (patch)
treefcee2236060a3b805995a4b0e3be01aab33d6f69
parent4358121adafa025b5d8751e6b6ede6a81ba97f88 (diff)
downloadandroid_external_f2fs-tools-d19dbfc9a6617d1644f21272354daeb16f064bf5.tar.gz
android_external_f2fs-tools-d19dbfc9a6617d1644f21272354daeb16f064bf5.tar.bz2
android_external_f2fs-tools-d19dbfc9a6617d1644f21272354daeb16f064bf5.zip
fsck.f2fs: LFS alloc_type must have free segment after blkoff
This patch checks alloc_type of current segment type. If it is LFS, the last of segment should have no valid block. Change-Id: I11411e894b92520a576f33dde3790a66500aae5e Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r--fsck/f2fs.h16
-rw-r--r--fsck/fsck.c15
-rw-r--r--fsck/fsck.h4
-rw-r--r--fsck/mount.c97
4 files changed, 131 insertions, 1 deletions
diff --git a/fsck/f2fs.h b/fsck/f2fs.h
index 034e0d1..f85fa73 100644
--- a/fsck/f2fs.h
+++ b/fsck/f2fs.h
@@ -356,6 +356,22 @@ static inline bool IS_VALID_BLK_ADDR(struct f2fs_sb_info *sbi, u32 addr)
return 1;
}
+static inline int IS_CUR_SEGNO(struct f2fs_sb_info *sbi, u32 segno, int type)
+{
+ int i;
+
+ for (i = 0; i < NO_CHECK_TYPE; i++) {
+ struct curseg_info *curseg = CURSEG_I(sbi, i);
+
+ if (type == i)
+ continue;
+
+ if (segno == curseg->segno)
+ return 1;
+ }
+ return 0;
+}
+
static inline u64 BLKOFF_FROM_MAIN(struct f2fs_sb_info *sbi, u64 blk_addr)
{
ASSERT(blk_addr >= SM_I(sbi)->main_blkaddr);
diff --git a/fsck/fsck.c b/fsck/fsck.c
index adc61d2..1b55c30 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -1368,13 +1368,24 @@ int check_curseg_offset(struct f2fs_sb_info *sbi)
for (i = 0; i < NO_CHECK_TYPE; i++) {
struct curseg_info *curseg = CURSEG_I(sbi, i);
struct seg_entry *se;
+ int j, nblocks;
se = get_seg_entry(sbi, curseg->segno);
if (f2fs_test_bit(curseg->next_blkoff,
- (const char *)se->cur_valid_map) == 1) {
+ (const char *)se->cur_valid_map)) {
ASSERT_MSG("Next block offset is not free, type:%d", i);
return -EINVAL;
}
+ if (curseg->alloc_type == SSR)
+ return 0;
+
+ nblocks = sbi->blocks_per_seg;
+ for (j = curseg->next_blkoff + 1; j < nblocks; j++) {
+ if (f2fs_test_bit(j, (const char *)se->cur_valid_map)) {
+ ASSERT_MSG("LFS must have free section:%d", i);
+ return -EINVAL;
+ }
+ }
}
return 0;
}
@@ -1528,6 +1539,8 @@ int fsck_verify(struct f2fs_sb_info *sbi)
if (force || (config.bug_on && config.fix_on && !config.ro)) {
fix_hard_links(sbi);
fix_nat_entries(sbi);
+ move_curseg_info(sbi, SM_I(sbi)->main_blkaddr);
+ write_curseg_info(sbi);
rewrite_sit_area_bitmap(sbi);
fix_checkpoint(sbi);
}
diff --git a/fsck/fsck.h b/fsck/fsck.h
index f6b8c53..4876914 100644
--- a/fsck/fsck.h
+++ b/fsck/fsck.h
@@ -132,6 +132,10 @@ extern void fsck_free(struct f2fs_sb_info *);
extern int f2fs_do_mount(struct f2fs_sb_info *);
extern void f2fs_do_umount(struct f2fs_sb_info *);
+extern void move_curseg_info(struct f2fs_sb_info *, u64);
+extern void write_curseg_info(struct f2fs_sb_info *);
+extern int find_next_free_block(struct f2fs_sb_info *, u64 *, int, int);
+
extern void print_raw_sb_info(struct f2fs_super_block *);
/* dump.c */
diff --git a/fsck/mount.c b/fsck/mount.c
index 99e2439..970b159 100644
--- a/fsck/mount.c
+++ b/fsck/mount.c
@@ -1133,6 +1133,103 @@ void rewrite_sit_area_bitmap(struct f2fs_sb_info *sbi)
}
}
+int find_next_free_block(struct f2fs_sb_info *sbi, u64 *to, int left, int type)
+{
+ struct seg_entry *se;
+ u32 segno;
+ u64 offset;
+
+ while (*to >= SM_I(sbi)->main_blkaddr &&
+ *to < F2FS_RAW_SUPER(sbi)->block_count) {
+ segno = GET_SEGNO(sbi, *to);
+ offset = OFFSET_IN_SEG(sbi, *to);
+
+ se = get_seg_entry(sbi, segno);
+
+ if (se->valid_blocks == sbi->blocks_per_seg)
+ goto next;
+
+ if (se->valid_blocks == 0 && !(segno % sbi->segs_per_sec) &&
+ !IS_CUR_SEGNO(sbi, segno, type)) {
+ struct seg_entry *se2;
+ int i;
+
+ for (i = 0; i < sbi->segs_per_sec; i++) {
+ se2 = get_seg_entry(sbi, segno + i);
+ if (se2->valid_blocks)
+ break;
+ }
+ if (i == sbi->segs_per_sec)
+ return 0;
+ }
+
+ if (se->type == type &&
+ !f2fs_test_bit(offset, (const char *)se->cur_valid_map))
+ return 0;
+next:
+ *to = left ? *to - 1: *to + 1;
+ }
+ return -1;
+}
+
+void move_curseg_info(struct f2fs_sb_info *sbi, u64 from)
+{
+ int i, ret;
+
+ /* update summary blocks having nullified journal entries */
+ for (i = 0; i < NO_CHECK_TYPE; i++) {
+ struct curseg_info *curseg = CURSEG_I(sbi, i);
+ u32 old_segno;
+ u64 ssa_blk, to;
+
+ /* update original SSA too */
+ ssa_blk = GET_SUM_BLKADDR(sbi, curseg->segno);
+ ret = dev_write_block(curseg->sum_blk, ssa_blk);
+ ASSERT(ret >= 0);
+
+ to = from;
+ ret = find_next_free_block(sbi, &to, 0, i);
+ ASSERT(ret == 0);
+
+ old_segno = curseg->segno;
+ curseg->segno = GET_SEGNO(sbi, to);
+ curseg->next_blkoff = OFFSET_IN_SEG(sbi, to);
+ curseg->alloc_type = SSR;
+
+ /* update new segno */
+ ssa_blk = GET_SUM_BLKADDR(sbi, curseg->segno);
+ ret = dev_read_block(curseg->sum_blk, ssa_blk);
+ ASSERT(ret >= 0);
+
+ /* update se->types */
+ reset_curseg(sbi, i);
+
+ DBG(0, "Move curseg[%d] %x -> %x after %"PRIx64"\n",
+ i, old_segno, curseg->segno, from);
+ }
+}
+
+void write_curseg_info(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_checkpoint *cp = F2FS_CKPT(sbi);
+ int i;
+
+ for (i = 0; i < NO_CHECK_TYPE; i++) {
+ cp->alloc_type[i] = CURSEG_I(sbi, i)->alloc_type;
+ if (i < CURSEG_HOT_NODE) {
+ set_cp(cur_data_segno[i], CURSEG_I(sbi, i)->segno);
+ set_cp(cur_data_blkoff[i],
+ CURSEG_I(sbi, i)->next_blkoff);
+ } else {
+ int n = i - CURSEG_HOT_NODE;
+
+ set_cp(cur_node_segno[n], CURSEG_I(sbi, i)->segno);
+ set_cp(cur_node_blkoff[n],
+ CURSEG_I(sbi, i)->next_blkoff);
+ }
+ }
+}
+
int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid,
struct f2fs_nat_entry *raw_nat)
{