Re: [f2fs-dev] [RFC PATCH v2] fsck.f2fs: rebuild qf_ino if quota node is unreachable
On 2018/7/26 20:35, Sheng Yong wrote: > If a quota node is corrupted, it may be unreachable. But its qf_ino in > super blocks is not cleared. To keep quota feature available, let's try > to rebuild a new quota node. > > Disk quota entries are written back according to data recorded in > the dict. quota_write_inode() will help to rebuild all quota structures > later. > > Signed-off-by: Sheng Yong > --- > v2->v1: calculate inode checksum when write quota inode, update commit msg > --- > fsck/fsck.c | 82 +--- > fsck/fsck.h | 1 + > fsck/mount.c | 7 +++-- > 3 files changed, 84 insertions(+), 6 deletions(-) > > diff --git a/fsck/fsck.c b/fsck/fsck.c > index e95dedf..5e68c1e 100644 > --- a/fsck/fsck.c > +++ b/fsck/fsck.c > @@ -10,6 +10,7 @@ > */ > #include "fsck.h" > #include "quotaio.h" > +#include "quotaio_v2.h" > #include > > char *tree_mark; > @@ -1697,13 +1698,80 @@ int fsck_chk_quota_node(struct f2fs_sb_info *sbi) > } > ret = fsck_chk_node_blk(sbi, NULL, ino, > F2FS_FT_REG_FILE, TYPE_INODE, _cnt, NULL); > - if (ret) > - ASSERT_MSG("wrong quota inode, qtype [%d] ino [0x%x]", > - qtype, ino); > + if (ret) { > + /* sanity_check_nid failed, node should be removed */ > + ASSERT_MSG("[0x%x] wrong quota inode", ino); > + if (c.fix_on) > + F2FS_FSCK(sbi)->corrupt_quotas = 1 << qtype; F2FS_FSCK(sbi)->corrupt_quotas |= 1 << qtype; > + } > } > return ret; > } > > +static nid_t prepare_rebuild_qf_inode(struct f2fs_sb_info *sbi, int qtype) > +{ > + struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); > + struct f2fs_summary sum; > + struct f2fs_node *qf_node; > + nid_t nid = QUOTA_INO(F2FS_RAW_SUPER(sbi), qtype); > + block_t node_blkaddr; > + > + DBG(1, "Rebuild Quota file (qtype [%3d] ino [0x%x])\n", qtype, nid); > + > + qf_node = calloc(F2FS_BLKSIZE, 1); > + if (!qf_node) { > + MSG(0, "\tError: calloc failed for qf_inode!!!\n"); > + return 0; > + } > + > + /* prepare qf_node */ > + qf_node->footer.nid = cpu_to_le32(nid); > + qf_node->footer.ino = cpu_to_le32(nid); > + qf_node->footer.cp_ver = cpu_to_le64(get_cp(checkpoint_ver)); > + > + qf_node->i.i_mode = cpu_to_le16(0x8180); > + qf_node->i.i_links = cpu_to_le32(1); > + qf_node->i.i_uid = cpu_to_le32(getuid()); > + qf_node->i.i_gid = cpu_to_le32(getgid()); Need to rebase last dev-test, using c.root_uid, c.root_gid here. > + qf_node->i.i_size = 0; > + qf_node->i.i_blocks = 1; > + qf_node->i.i_atime = cpu_to_le32(time(NULL)); > + qf_node->i.i_atime_nsec = 0; > + qf_node->i.i_ctime = cpu_to_le32(time(NULL)); > + qf_node->i.i_ctime_nsec = 0; > + qf_node->i.i_mtime = cpu_to_le32(time(NULL)); > + qf_node->i.i_mtime_nsec = 0; > + qf_node->i.i_generation = 0; > + qf_node->i.i_xattr_nid = 0; > + qf_node->i.i_flags = FS_IMMUTABLE_FL; > + qf_node->i.i_current_depth = cpu_to_le32(1); We don't need to init i_current_depth for regular inode. > + qf_node->i.i_dir_level = DEF_DIR_LEVEL; Ditto. > + if (c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR)) { > + qf_node->i.i_inline = F2FS_EXTRA_ATTR; > + qf_node->i.i_extra_isize = > + cpu_to_le16(F2FS_TOTAL_EXTRA_ATTR_SIZE); > + } > + if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CRTIME)) { > + qf_node->i.i_crtime = cpu_to_le32(time(NULL)); > + qf_node->i.i_crtime_nsec = 0; > + } > + > + /* write back qf inode */ > + node_blkaddr = 0; > + set_summary(, nid, 0, 0); > + reserve_new_block(sbi, _blkaddr, , CURSEG_HOT_NODE); > + update_nat_blkaddr(sbi, nid, nid, node_blkaddr); > + if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM)) > + qf_node->i.i_inode_checksum = > + cpu_to_le32(f2fs_inode_chksum(qf_node)); > + ASSERT(dev_write_block(qf_node, node_blkaddr) >= 0); > + DBG(1, "Write new qf_node to blk %#x\n", node_blkaddr); > + f2fs_clear_bit(nid, F2FS_FSCK(sbi)->nat_area_bitmap); > + > + free(qf_node); > + return nid; > +} > + > int fsck_chk_quota_files(struct f2fs_sb_info *sbi) > { > struct f2fs_fsck *fsck = F2FS_FSCK(sbi); > @@ -1722,6 +1790,12 @@ int fsck_chk_quota_files(struct f2fs_sb_info *sbi) > if (!ino) > continue; > > + if (fsck->corrupt_quotas & (1 << qtype) && c.fix_on) { > + ino = prepare_rebuild_qf_inode(sbi, qtype); > + if (!ino) > + continue; > + } > + > DBG(1, "Checking Quota file ([%3d] ino [0x%x])\n", qtype, ino); >
[f2fs-dev] [RFC PATCH v2] fsck.f2fs: rebuild qf_ino if quota node is unreachable
If a quota node is corrupted, it may be unreachable. But its qf_ino in super blocks is not cleared. To keep quota feature available, let's try to rebuild a new quota node. Disk quota entries are written back according to data recorded in the dict. quota_write_inode() will help to rebuild all quota structures later. Signed-off-by: Sheng Yong --- v2->v1: calculate inode checksum when write quota inode, update commit msg --- fsck/fsck.c | 82 +--- fsck/fsck.h | 1 + fsck/mount.c | 7 +++-- 3 files changed, 84 insertions(+), 6 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index e95dedf..5e68c1e 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -10,6 +10,7 @@ */ #include "fsck.h" #include "quotaio.h" +#include "quotaio_v2.h" #include char *tree_mark; @@ -1697,13 +1698,80 @@ int fsck_chk_quota_node(struct f2fs_sb_info *sbi) } ret = fsck_chk_node_blk(sbi, NULL, ino, F2FS_FT_REG_FILE, TYPE_INODE, _cnt, NULL); - if (ret) - ASSERT_MSG("wrong quota inode, qtype [%d] ino [0x%x]", - qtype, ino); + if (ret) { + /* sanity_check_nid failed, node should be removed */ + ASSERT_MSG("[0x%x] wrong quota inode", ino); + if (c.fix_on) + F2FS_FSCK(sbi)->corrupt_quotas = 1 << qtype; + } } return ret; } +static nid_t prepare_rebuild_qf_inode(struct f2fs_sb_info *sbi, int qtype) +{ + struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); + struct f2fs_summary sum; + struct f2fs_node *qf_node; + nid_t nid = QUOTA_INO(F2FS_RAW_SUPER(sbi), qtype); + block_t node_blkaddr; + + DBG(1, "Rebuild Quota file (qtype [%3d] ino [0x%x])\n", qtype, nid); + + qf_node = calloc(F2FS_BLKSIZE, 1); + if (!qf_node) { + MSG(0, "\tError: calloc failed for qf_inode!!!\n"); + return 0; + } + + /* prepare qf_node */ + qf_node->footer.nid = cpu_to_le32(nid); + qf_node->footer.ino = cpu_to_le32(nid); + qf_node->footer.cp_ver = cpu_to_le64(get_cp(checkpoint_ver)); + + qf_node->i.i_mode = cpu_to_le16(0x8180); + qf_node->i.i_links = cpu_to_le32(1); + qf_node->i.i_uid = cpu_to_le32(getuid()); + qf_node->i.i_gid = cpu_to_le32(getgid()); + qf_node->i.i_size = 0; + qf_node->i.i_blocks = 1; + qf_node->i.i_atime = cpu_to_le32(time(NULL)); + qf_node->i.i_atime_nsec = 0; + qf_node->i.i_ctime = cpu_to_le32(time(NULL)); + qf_node->i.i_ctime_nsec = 0; + qf_node->i.i_mtime = cpu_to_le32(time(NULL)); + qf_node->i.i_mtime_nsec = 0; + qf_node->i.i_generation = 0; + qf_node->i.i_xattr_nid = 0; + qf_node->i.i_flags = FS_IMMUTABLE_FL; + qf_node->i.i_current_depth = cpu_to_le32(1); + qf_node->i.i_dir_level = DEF_DIR_LEVEL; + if (c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR)) { + qf_node->i.i_inline = F2FS_EXTRA_ATTR; + qf_node->i.i_extra_isize = + cpu_to_le16(F2FS_TOTAL_EXTRA_ATTR_SIZE); + } + if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CRTIME)) { + qf_node->i.i_crtime = cpu_to_le32(time(NULL)); + qf_node->i.i_crtime_nsec = 0; + } + + /* write back qf inode */ + node_blkaddr = 0; + set_summary(, nid, 0, 0); + reserve_new_block(sbi, _blkaddr, , CURSEG_HOT_NODE); + update_nat_blkaddr(sbi, nid, nid, node_blkaddr); + if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM)) + qf_node->i.i_inode_checksum = + cpu_to_le32(f2fs_inode_chksum(qf_node)); + ASSERT(dev_write_block(qf_node, node_blkaddr) >= 0); + DBG(1, "Write new qf_node to blk %#x\n", node_blkaddr); + f2fs_clear_bit(nid, F2FS_FSCK(sbi)->nat_area_bitmap); + + free(qf_node); + return nid; +} + int fsck_chk_quota_files(struct f2fs_sb_info *sbi) { struct f2fs_fsck *fsck = F2FS_FSCK(sbi); @@ -1722,6 +1790,12 @@ int fsck_chk_quota_files(struct f2fs_sb_info *sbi) if (!ino) continue; + if (fsck->corrupt_quotas & (1 << qtype) && c.fix_on) { + ino = prepare_rebuild_qf_inode(sbi, qtype); + if (!ino) + continue; + } + DBG(1, "Checking Quota file ([%3d] ino [0x%x])\n", qtype, ino); needs_writeout = 0; ret = quota_compare_and_update(sbi, qtype, _writeout, @@ -1733,7 +1807,7 @@ int fsck_chk_quota_files(struct f2fs_sb_info *sbi) /* Something is wrong */ if (c.fix_on) { - DBG(0, "Fixing Quota file ([%3d] ino