Re: [f2fs-dev] [RFC PATCH v2] fsck.f2fs: rebuild qf_ino if quota node is unreachable

2018-07-27 Thread Chao Yu
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

2018-07-26 Thread Sheng Yong
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