Messages in this thread Patch in this message | | | From | Robin Hsu <> | Subject | [PATCH] fsck.f2fs: add basic compress related check/fix | Date | Tue, 29 Jun 2021 13:36:31 +0800 |
| |
From: Robin Hsu <robinhsu@google.com>
* check/fix i_compr_blocks * check/fix compressed flag in i_flags when compression is not supported.
Signed-off-by: Robin Hsu <robinhsu@google.com> --- fsck/fsck.c | 160 +++++++++++++++++++++++++++++++++++----------- fsck/fsck.h | 14 ++-- fsck/main.c | 6 +- include/f2fs_fs.h | 15 +++++ 4 files changed, 151 insertions(+), 44 deletions(-)
diff --git a/fsck/fsck.c b/fsck/fsck.c index 80a6d8e..17e3eec 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -533,7 +533,8 @@ out: int fsck_chk_node_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, u32 nid, enum FILE_TYPE ftype, enum NODE_TYPE ntype, - u32 *blk_cnt, struct child_info *child) + u32 *blk_cnt, struct f2fs_compr_blk_cnt *cbc, + struct child_info *child) { struct node_info ni; struct f2fs_node *node_blk = NULL; @@ -547,7 +548,8 @@ int fsck_chk_node_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, if (ntype == TYPE_INODE) { struct f2fs_fsck *fsck = F2FS_FSCK(sbi); - fsck_chk_inode_blk(sbi, nid, ftype, node_blk, blk_cnt, &ni, child); + fsck_chk_inode_blk(sbi, nid, ftype, node_blk, blk_cnt, cbc, + &ni, child); quota_add_inode_usage(fsck->qctx, nid, &node_blk->i); } else { switch (ntype) { @@ -555,19 +557,19 @@ int fsck_chk_node_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, f2fs_set_main_bitmap(sbi, ni.blk_addr, CURSEG_WARM_NODE); fsck_chk_dnode_blk(sbi, inode, nid, ftype, node_blk, - blk_cnt, child, &ni); + blk_cnt, cbc, child, &ni); break; case TYPE_INDIRECT_NODE: f2fs_set_main_bitmap(sbi, ni.blk_addr, CURSEG_COLD_NODE); fsck_chk_idnode_blk(sbi, inode, ftype, node_blk, - blk_cnt, child); + blk_cnt, cbc, child); break; case TYPE_DOUBLE_INDIRECT_NODE: f2fs_set_main_bitmap(sbi, ni.blk_addr, CURSEG_COLD_NODE); fsck_chk_didnode_blk(sbi, inode, ftype, node_blk, - blk_cnt, child); + blk_cnt, cbc, child); break; default: ASSERT(0); @@ -667,7 +669,8 @@ void fsck_reada_all_direct_node_blocks(struct f2fs_sb_info *sbi, /* start with valid nid and blkaddr */ void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid, enum FILE_TYPE ftype, struct f2fs_node *node_blk, - u32 *blk_cnt, struct node_info *ni, struct child_info *child_d) + u32 *blk_cnt, struct f2fs_compr_blk_cnt *cbc, + struct node_info *ni, struct child_info *child_d) { struct f2fs_fsck *fsck = F2FS_FSCK(sbi); struct child_info child; @@ -675,6 +678,12 @@ void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid, u32 i_links = le32_to_cpu(node_blk->i.i_links); u64 i_size = le64_to_cpu(node_blk->i.i_size); u64 i_blocks = le64_to_cpu(node_blk->i.i_blocks); + bool compr_supported = c.feature & cpu_to_le32(F2FS_FEATURE_COMPRESSION); + u32 i_flags = le32_to_cpu(node_blk->i.i_flags); + bool compressed = (i_flags & F2FS_COMPR_FL)? true: false; + bool compr_rel = (node_blk->i.i_inline & F2FS_COMPRESS_RELEASED)? + true : false; + u64 i_compr_blocks = le64_to_cpu(node_blk->i.i_compr_blocks); nid_t i_xattr_nid = le32_to_cpu(node_blk->i.i_xattr_nid); int ofs; char *en; @@ -683,7 +692,23 @@ void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid, unsigned short i_gc_failures; int need_fix = 0; int ret; + u32 cluster_size = 1 << node_blk->i.i_log_cluster_size; + if (!compr_supported && compressed) { + /* + * The 'compression' flag in i_flags affects the traverse of + * the node tree. Thus, it must be fixed unconditionally + * in the memory (node_blk). + */ + node_blk->i.i_flags &= ~cpu_to_le32(F2FS_COMPR_FL); + compressed = false; + if (c.fix_on) { + need_fix = 1; + FIX_MSG("[0x%x] i_flags=0x%x -> 0x%x", + nid, i_flags, node_blk->i.i_flags); + } + i_flags &= ~F2FS_COMPR_FL; + } memset(&child, 0, sizeof(child)); child.links = 2; child.p_ino = nid; @@ -897,31 +922,45 @@ void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid, /* check extent info */ check_extent_info(&child, blkaddr, 0); + if (blkaddr == NULL_ADDR) + continue; if (blkaddr == COMPRESS_ADDR) { - if (node_blk->i.i_compr_blocks) { + if (!compressed || (child.pgofs & + (cluster_size - 1)) != 0) { + if (c.fix_on) { + node_blk->i.i_addr[ofs + idx] = + NULL_ADDR; + need_fix = 1; + FIX_MSG("[0x%x] i_addr[%d] = 0", nid, + ofs + idx); + } + continue; + } + if (!compr_rel) { fsck->chk.valid_blk_cnt++; *blk_cnt = *blk_cnt + 1; + cbc->cheader_pgofs = child.pgofs; + cbc->cnt++; } continue; } - - if (blkaddr != 0) { - ret = fsck_chk_data_blk(sbi, - IS_CASEFOLDED(&node_blk->i), - blkaddr, - &child, (i_blocks == *blk_cnt), - ftype, nid, idx, ni->version, - file_is_encrypt(&node_blk->i)); - if (!ret) { - *blk_cnt = *blk_cnt + 1; - if (cur_qtype != -1 && blkaddr != NEW_ADDR) - qf_last_blkofs[cur_qtype] = child.pgofs; - } else if (c.fix_on) { - node_blk->i.i_addr[ofs + idx] = 0; - need_fix = 1; - FIX_MSG("[0x%x] i_addr[%d] = 0", - nid, ofs + idx); - } + if (!compr_rel && blkaddr == NEW_ADDR && + child.pgofs - cbc->cheader_pgofs < cluster_size) + cbc->cnt++; + ret = fsck_chk_data_blk(sbi, + IS_CASEFOLDED(&node_blk->i), + blkaddr, + &child, (i_blocks == *blk_cnt), + ftype, nid, idx, ni->version, + file_is_encrypt(&node_blk->i)); + if (!ret) { + *blk_cnt = *blk_cnt + 1; + if (cur_qtype != -1 && blkaddr != NEW_ADDR) + qf_last_blkofs[cur_qtype] = child.pgofs; + } else if (c.fix_on) { + node_blk->i.i_addr[ofs + idx] = 0; + need_fix = 1; + FIX_MSG("[0x%x] i_addr[%d] = 0", nid, ofs + idx); } } @@ -948,7 +987,7 @@ void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid, goto skip; ret = fsck_chk_node_blk(sbi, &node_blk->i, i_nid, - ftype, ntype, blk_cnt, &child); + ftype, ntype, blk_cnt, cbc, &child); if (!ret) { *blk_cnt = *blk_cnt + 1; } else if (ret == -EINVAL) { @@ -992,6 +1031,16 @@ check: nid, i_blocks, *blk_cnt); } } + + if (compressed && i_compr_blocks != cbc->cnt) { + if (c.fix_on) { + node_blk->i.i_compr_blocks = cpu_to_le64(cbc->cnt); + need_fix = 1; + FIX_MSG("[0x%x] i_compr_blocks=0x%08"PRIx64" -> 0x%x", + nid, i_compr_blocks, cbc->cnt); + } + } + skip_blkcnt_fix: en = malloc(F2FS_PRINT_NAMELEN); ASSERT(en); @@ -1130,27 +1179,48 @@ skip_blkcnt_fix: int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, u32 nid, enum FILE_TYPE ftype, struct f2fs_node *node_blk, - u32 *blk_cnt, struct child_info *child, struct node_info *ni) + u32 *blk_cnt, struct f2fs_compr_blk_cnt *cbc, + struct child_info *child, struct node_info *ni) { int idx, ret; int need_fix = 0; child->p_ino = nid; child->pp_ino = le32_to_cpu(inode->i_pino); + u32 i_flags = le32_to_cpu(inode->i_flags); + bool compressed = (i_flags & F2FS_COMPR_FL)? true: false; + bool compr_rel = (inode->i_inline & F2FS_COMPRESS_RELEASED)? + true : false; + u32 cluster_size = 1 << inode->i_log_cluster_size; for (idx = 0; idx < ADDRS_PER_BLOCK(inode); idx++, child->pgofs++) { block_t blkaddr = le32_to_cpu(node_blk->dn.addr[idx]); check_extent_info(child, blkaddr, 0); - if (blkaddr == 0x0) + if (blkaddr == NULL_ADDR) continue; if (blkaddr == COMPRESS_ADDR) { - if (inode->i_compr_blocks) { + if (!compressed || (child->pgofs & + (cluster_size - 1)) != 0) { + if (c.fix_on) { + node_blk->dn.addr[idx] = NULL_ADDR; + need_fix = 1; + FIX_MSG("[0x%x] dn.addr[%d] = 0", nid, + idx); + } + continue; + } + if (!compr_rel) { F2FS_FSCK(sbi)->chk.valid_blk_cnt++; *blk_cnt = *blk_cnt + 1; + cbc->cheader_pgofs = child->pgofs; + cbc->cnt++; } continue; } + if (!compr_rel && blkaddr == NEW_ADDR && child->pgofs - + cbc->cheader_pgofs < cluster_size) + cbc->cnt++; ret = fsck_chk_data_blk(sbi, IS_CASEFOLDED(inode), blkaddr, child, le64_to_cpu(inode->i_blocks) == *blk_cnt, ftype, @@ -1161,7 +1231,7 @@ int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, if (cur_qtype != -1 && blkaddr != NEW_ADDR) qf_last_blkofs[cur_qtype] = child->pgofs; } else if (c.fix_on) { - node_blk->dn.addr[idx] = 0; + node_blk->dn.addr[idx] = NULL_ADDR; need_fix = 1; FIX_MSG("[0x%x] dn.addr[%d] = 0", nid, idx); } @@ -1175,7 +1245,7 @@ int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, int fsck_chk_idnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt, - struct child_info *child) + struct f2fs_compr_blk_cnt *cbc, struct child_info *child) { int need_fix = 0, ret; int i = 0; @@ -1187,7 +1257,8 @@ int fsck_chk_idnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, goto skip; ret = fsck_chk_node_blk(sbi, inode, le32_to_cpu(node_blk->in.nid[i]), - ftype, TYPE_DIRECT_NODE, blk_cnt, child); + ftype, TYPE_DIRECT_NODE, blk_cnt, + cbc, child); if (!ret) *blk_cnt = *blk_cnt + 1; else if (ret == -EINVAL) { @@ -1217,7 +1288,7 @@ skip: int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt, - struct child_info *child) + struct f2fs_compr_blk_cnt *cbc, struct child_info *child) { int i = 0; int need_fix = 0, ret = 0; @@ -1229,7 +1300,7 @@ int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, goto skip; ret = fsck_chk_node_blk(sbi, inode, le32_to_cpu(node_blk->in.nid[i]), - ftype, TYPE_INDIRECT_NODE, blk_cnt, child); + ftype, TYPE_INDIRECT_NODE, blk_cnt, cbc, child); if (!ret) *blk_cnt = *blk_cnt + 1; else if (ret == -EINVAL) { @@ -1474,6 +1545,7 @@ static int __chk_dentries(struct f2fs_sb_info *sbi, int casefolded, enum FILE_TYPE ftype; int dentries = 0; u32 blk_cnt; + struct f2fs_compr_blk_cnt cbc; u8 *name; char en[F2FS_PRINT_NAMELEN]; u16 name_len; @@ -1613,10 +1685,12 @@ static int __chk_dentries(struct f2fs_sb_info *sbi, int casefolded, dentry, max, i, last_blk, enc_name); blk_cnt = 1; + cbc.cnt = 0; + cbc.cheader_pgofs = CHEADER_PGOFS_NONE; child->i_namelen = name_len; ret = fsck_chk_node_blk(sbi, NULL, le32_to_cpu(dentry[i].ino), - ftype, TYPE_INODE, &blk_cnt, child); + ftype, TYPE_INODE, &blk_cnt, &cbc, child); if (ret && c.fix_on) { int j; @@ -1753,6 +1827,7 @@ int fsck_chk_data_blk(struct f2fs_sb_info *sbi, int casefolded, int fsck_chk_orphan_node(struct f2fs_sb_info *sbi) { u32 blk_cnt = 0; + struct f2fs_compr_blk_cnt cbc = {0, CHEADER_PGOFS_NONE}; block_t start_blk, orphan_blkaddr, i, j; struct f2fs_orphan_block *orphan_blk, *new_blk; struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); @@ -1784,6 +1859,8 @@ int fsck_chk_orphan_node(struct f2fs_sb_info *sbi) DBG(1, "[%3d] ino [0x%x]\n", i, ino); struct node_info ni; blk_cnt = 1; + cbc.cnt = 0; + cbc.cheader_pgofs = CHEADER_PGOFS_NONE; if (c.preen_mode == PREEN_MODE_1 && !c.fix_on) { get_node_info(sbi, ino, &ni); @@ -1799,7 +1876,7 @@ int fsck_chk_orphan_node(struct f2fs_sb_info *sbi) ret = fsck_chk_node_blk(sbi, NULL, ino, F2FS_FT_ORPHAN, TYPE_INODE, &blk_cnt, - NULL); + &cbc, NULL); if (!ret) new_blk->ino[new_entry_count++] = orphan_blk->ino[j]; @@ -1829,6 +1906,7 @@ int fsck_chk_quota_node(struct f2fs_sb_info *sbi) enum quota_type qtype; int ret = 0; u32 blk_cnt = 0; + struct f2fs_compr_blk_cnt cbc = {0, CHEADER_PGOFS_NONE}; for (qtype = 0; qtype < F2FS_MAX_QUOTAS; qtype++) { cur_qtype = qtype; @@ -1839,6 +1917,8 @@ int fsck_chk_quota_node(struct f2fs_sb_info *sbi) DBG(1, "qtype [%d] ino [0x%x]\n", qtype, ino); blk_cnt = 1; + cbc.cnt = 0; + cbc.cheader_pgofs = CHEADER_PGOFS_NONE; if (c.preen_mode == PREEN_MODE_1 && !c.fix_on) { get_node_info(sbi, ino, &ni); @@ -1848,7 +1928,8 @@ int fsck_chk_quota_node(struct f2fs_sb_info *sbi) continue; } ret = fsck_chk_node_blk(sbi, NULL, ino, - F2FS_FT_REG_FILE, TYPE_INODE, &blk_cnt, NULL); + F2FS_FT_REG_FILE, TYPE_INODE, &blk_cnt, + &cbc, NULL); if (ret) { ASSERT_MSG("wrong quota inode, qtype [%d] ino [0x%x]", qtype, ino); @@ -2753,6 +2834,7 @@ static int fsck_reconnect_file(struct f2fs_sb_info *sbi) struct node_info ni; char *reconnect_bitmap; u32 blk_cnt; + struct f2fs_compr_blk_cnt cbc; nid_t nid; int err, cnt = 0, ftype; @@ -2796,8 +2878,10 @@ static int fsck_reconnect_file(struct f2fs_sb_info *sbi) DBG(1, "Check inode 0x%x\n", nid); blk_cnt = 1; + cbc.cnt = 0; + cbc.cheader_pgofs = CHEADER_PGOFS_NONE; fsck_chk_inode_blk(sbi, nid, ftype, node, - &blk_cnt, &ni, NULL); + &blk_cnt, &cbc, &ni, NULL); f2fs_set_bit(nid, reconnect_bitmap); } diff --git a/fsck/fsck.h b/fsck/fsck.h index b9dcd5c..37ff6b2 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -160,16 +160,20 @@ extern int fsck_sanity_check_nid(struct f2fs_sb_info *, u32, struct node_info *); extern int fsck_chk_node_blk(struct f2fs_sb_info *, struct f2fs_inode *, u32, enum FILE_TYPE, enum NODE_TYPE, u32 *, - struct child_info *); + struct f2fs_compr_blk_cnt *, struct child_info *); extern void fsck_chk_inode_blk(struct f2fs_sb_info *, u32, enum FILE_TYPE, - struct f2fs_node *, u32 *, struct node_info *, struct child_info *); + struct f2fs_node *, u32 *, struct f2fs_compr_blk_cnt *, + struct node_info *, struct child_info *); extern int fsck_chk_dnode_blk(struct f2fs_sb_info *, struct f2fs_inode *, u32, enum FILE_TYPE, struct f2fs_node *, u32 *, - struct child_info *, struct node_info *); + struct f2fs_compr_blk_cnt *, struct child_info *, + struct node_info *); extern int fsck_chk_idnode_blk(struct f2fs_sb_info *, struct f2fs_inode *, - enum FILE_TYPE, struct f2fs_node *, u32 *, struct child_info *); + enum FILE_TYPE, struct f2fs_node *, u32 *, + struct f2fs_compr_blk_cnt *, struct child_info *); extern int fsck_chk_didnode_blk(struct f2fs_sb_info *, struct f2fs_inode *, - enum FILE_TYPE, struct f2fs_node *, u32 *, struct child_info *); + enum FILE_TYPE, struct f2fs_node *, u32 *, + struct f2fs_compr_blk_cnt *, struct child_info *); extern int fsck_chk_data_blk(struct f2fs_sb_info *, int, u32, struct child_info *, int, enum FILE_TYPE, u32, u16, u8, int); extern int fsck_chk_dentry_blk(struct f2fs_sb_info *, int, diff --git a/fsck/main.c b/fsck/main.c index c0b871b..b917d2e 100644 --- a/fsck/main.c +++ b/fsck/main.c @@ -812,6 +812,7 @@ static int do_fsck(struct f2fs_sb_info *sbi) struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); u32 flag = le32_to_cpu(ckpt->ckpt_flags); u32 blk_cnt; + struct f2fs_compr_blk_cnt cbc; errcode_t ret; fsck_init(sbi); @@ -859,6 +860,9 @@ static int do_fsck(struct f2fs_sb_info *sbi) /* Traverse all block recursively from root inode */ blk_cnt = 1; + cbc.cnt = 0; + cbc.cheader_pgofs = CHEADER_PGOFS_NONE; + if (c.feature & cpu_to_le32(F2FS_FEATURE_QUOTA_INO)) { ret = quota_init_context(sbi); @@ -869,7 +873,7 @@ static int do_fsck(struct f2fs_sb_info *sbi) } fsck_chk_orphan_node(sbi); fsck_chk_node_blk(sbi, NULL, sbi->root_ino_num, - F2FS_FT_DIR, TYPE_INODE, &blk_cnt, NULL); + F2FS_FT_DIR, TYPE_INODE, &blk_cnt, &cbc, NULL); fsck_chk_quota_files(sbi); ret = fsck_verify(sbi); diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h index 8969ae2..7a56326 100644 --- a/include/f2fs_fs.h +++ b/include/f2fs_fs.h @@ -936,6 +936,21 @@ struct f2fs_extent { #define F2FS_CASEFOLD_FL 0x40000000 /* Casefolded file */ #define IS_CASEFOLDED(dir) ((dir)->i_flags & F2FS_CASEFOLD_FL) +/* + * fsck i_compr_blocks counting helper + */ +struct f2fs_compr_blk_cnt { + /* counting i_compr_blocks, init 0 */ + u32 cnt; + + /* + * previous seen compression header (COMPR_ADDR) page offsets, + * use CHEADER_PGOFS_NONE for none + */ + u32 cheader_pgofs; +}; +#define CHEADER_PGOFS_NONE ((u32) -(1<<MAX_COMPRESS_LOG_SIZE)) + /* * inode flags */ -- 2.32.0.93.g670b81a890-goog
| |