From nobody Sat Feb 7 18:20:31 2026 Received: from mail-pl1-f174.google.com (mail-pl1-f174.google.com [209.85.214.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B4AE7219A63 for ; Tue, 29 Apr 2025 17:55:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745949350; cv=none; b=q6sUyoFZROwzpcRib1cxodLsCzWQOo0RtgiV5CDEsrViVBMnKpmweF5mk7k/wZCqDDMgLMWA8XL3429uKiaXnAasY9v1l2hVJqJwuxcp2LTlwKol4pHC6VW3nkaBbMbShHBo5fCZscccQjuSmEiope0nr0uFQqHKNfVu6SmqXwA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745949350; c=relaxed/simple; bh=4B7bppnAiSmI4/0Er+kmjPFeLjZa57hXX3HXnZWUwtY=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=OgFqnrYq9E8+e4OMYlFurxDDnESz/SUYWCe7jg2KiPIZGPHQUW/TgYrybEuJlp7MlnxIVUI3GjVzaCm0DxcaQeEkycyQmA3vwGMnvkzodqUrNuanUCMbClZJUTOTvOIkPh/EO3P3ZCtd2auX240020cG/ddTe4GfxuicpuAn1+A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=JLv0CnIz; arc=none smtp.client-ip=209.85.214.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="JLv0CnIz" Received: by mail-pl1-f174.google.com with SMTP id d9443c01a7336-22401f4d35aso78389965ad.2 for ; Tue, 29 Apr 2025 10:55:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1745949348; x=1746554148; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=qc+17LaPQ8JizHVPq3DroMULp5vNZlGZD0lL4t82yXo=; b=JLv0CnIzebO1jLqN8hKU8ioerTTs3w1iCLL/xEtb3Dczwwh2askevEgz7H3wxo/fZD clPXXE2n/cCjrPLQygQxLFT6DIyCdh2AcIWKht0p4vL6G45QllGL8I0/kaat8WGKFEj+ xb7xlPO3Gl0mGp44ecoL+fDEIjvBmURS7eqsSWJI/n8OyfQWbzDV7ybvI0GISfs2MM7E dxOn/aQNnSNWckz/lQd6MVfCkZDlvZhcvPldwWh2sAXMt4dyomtxJJ/q4QaqPou1oCen FLSP/sEHsI1r263gWbDuqJOdEa84ge0b4GGL9slpOpvxa5gBw6tNwIx7YWs3/huOFiBV jKfw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745949348; x=1746554148; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=qc+17LaPQ8JizHVPq3DroMULp5vNZlGZD0lL4t82yXo=; b=sJFk6F6jGgFIKd49pzDfwdKJuTCLSv9OLz3LuM5Pikro18ckfX9DBxbuxxGu4MRVzw RB0xusxww0joEbkKHesM/v21G+VpfCmdTczIY45FitN5+P1273xvoXC52lIJJYGYQbAc tVake8EqIh2foN5fSupAr17sEtwvLe6rxa+gnvJO1FL8Q7m8v0+05zniGCilmhSmmmdo DvD+GxbwcdqzYvFQoPOZra1n52YHm+S85gaBFFR/Y76dyaMIA81YsVxNfAeqT991GGvj PDphICkuIC2vQ3kS1IR8hSYHEszfCTvQNcx8lCFirxJhG2PIOapO1g/+cjna1omy5uPU iB5A== X-Gm-Message-State: AOJu0Yxjo1U5YZbFhNqUV5In5WZcOBz/Clduo1t2r0vd0gD7ceUsOJ3R DaAdcUgK2cDeOl61PErunOY9UjhjQEaDJ9IP1y98H0UugEMUn+cOdDtZ0Q== X-Gm-Gg: ASbGncs+nXyMZQIYZyMc2VHcdHTIB84WJ/ogoQ31wKI6jxTtAgAVlf4CNAeaEgf7+/6 1y+uJl7TM81iGN75+XWOaS2pWcwS0rdiSjNSaPdi/RiTykWYfltcc5NQxXprbLbHdfwwFtDgDMt fCPbITtK12B4enAhPvEmSaFD73YEpwfpaeKtOhdSlQkBPmuhHN68tzWHmM25gKSYyKLLHxpglHc 5zpVDAQN7sAYMzyhlJWdb8iFjhuyuAaZuxQq01bg1vcwSTVfRzOzl2aXkqDEyV17Qj3dQRamtKg IN0f+1VeyYjYeRd1R8rZRYZ0lRqkuG1sLG1l2eqAolINBZjQqq4oMoSTW68dMp5LA7C3sY5vTrq 1w1WAgPV/pMaYEulOpG6dvY+HUlsZGLtO X-Google-Smtp-Source: AGHT+IHPaibhu6GQ8bFDk1kc3TnuhGRSK6eSgriokxkuPiGYsv+TZoot/0+SaG89GxW829eCiyNpPQ== X-Received: by 2002:a17:902:c401:b0:224:1d1c:8837 with SMTP id d9443c01a7336-22df34fc2c6mr4212135ad.19.1745949347518; Tue, 29 Apr 2025 10:55:47 -0700 (PDT) Received: from daehojeong-desktop.mtv.corp.google.com ([2a00:79e0:2e14:7:324e:5e26:e3c0:12f9]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-22db50e751dsm106113535ad.142.2025.04.29.10.55.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 29 Apr 2025 10:55:46 -0700 (PDT) From: Daeho Jeong To: linux-kernel@vger.kernel.org, linux-f2fs-devel@lists.sourceforge.net, kernel-team@android.com Cc: Daeho Jeong Subject: [PATCH v4] f2fs-tools: introduce fault injection to fsck Date: Tue, 29 Apr 2025 10:55:40 -0700 Message-ID: <20250429175540.2928130-1-daeho43@gmail.com> X-Mailer: git-send-email 2.49.0.901.g37484f566f-goog Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Daeho Jeong Due to the difficulty of intentionally corrupting specific metadata on some storage devices like zoned storage devices, it is challenging to effectively verify fsck functionality. To facilitate this verification, it is necessary to add a fault injection mode. Signed-off-by: Daeho Jeong --- v4: fix print type and typos in man page v3: set limit on fault counts v2: print fault injection result --- fsck/fsck.c | 123 +++++++++++++++++++++++++++++++++++----------- fsck/main.c | 22 +++++++++ fsck/mkquota.c | 3 ++ include/f2fs_fs.h | 58 ++++++++++++++++++++++ man/fsck.f2fs.8 | 36 ++++++++++++++ 5 files changed, 213 insertions(+), 29 deletions(-) diff --git a/fsck/fsck.c b/fsck/fsck.c index 8155cbd..b18e692 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -16,6 +16,20 @@ char *tree_mark; uint32_t tree_mark_size =3D 256; =20 +const char *f2fs_fault_name[FAULT_MAX] =3D { + [FAULT_SEG_TYPE] =3D "FAULT_SEG_TYPE", + [FAULT_SUM_TYPE] =3D "FAULT_SUM_TYPE", + [FAULT_SUM_ENT] =3D "FAULT_SUM_ENTRY", + [FAULT_NAT] =3D "FAULT_NAT_ENTRY", + [FAULT_NODE] =3D "FAULT_NODE_BLOCK", + [FAULT_XATTR_ENT] =3D "FAULT_XATTR_ENTRY", + [FAULT_COMPR] =3D "FAULT_COMPR_TYPE", + [FAULT_INODE] =3D "FAULT_INODE_ENTRY", + [FAULT_DENTRY] =3D "FAULT_DENTRY_BLOCK", + [FAULT_DATA] =3D "FAULT_DATA_BLOCK", + [FAULT_QUOTA] =3D "FAULT_QUOTA", +}; + int f2fs_set_main_bitmap(struct f2fs_sb_info *sbi, u32 blk, int type) { struct f2fs_fsck *fsck =3D F2FS_FSCK(sbi); @@ -23,9 +37,9 @@ int f2fs_set_main_bitmap(struct f2fs_sb_info *sbi, u32 bl= k, int type) int fix =3D 0; =20 se =3D get_seg_entry(sbi, GET_SEGNO(sbi, blk)); - if (se->type >=3D NO_CHECK_TYPE) - fix =3D 1; - else if (IS_DATASEG(se->type) !=3D IS_DATASEG(type)) + if (time_to_inject(FAULT_SEG_TYPE) || + (se->type >=3D NO_CHECK_TYPE) || + (IS_DATASEG(se->type) !=3D IS_DATASEG(type))) fix =3D 1; =20 /* just check data and node types */ @@ -168,7 +182,8 @@ static int is_valid_ssa_node_blk(struct f2fs_sb_info *s= bi, u32 nid, =20 sum_blk =3D get_sum_block(sbi, segno, &type); =20 - if (type !=3D SEG_TYPE_NODE && type !=3D SEG_TYPE_CUR_NODE) { + if (time_to_inject(FAULT_SUM_TYPE) || + (type !=3D SEG_TYPE_NODE && type !=3D SEG_TYPE_CUR_NODE)) { /* can't fix current summary, then drop the block */ if (!c.fix_on || type < 0) { ASSERT_MSG("Summary footer is not for node segment"); @@ -189,7 +204,8 @@ static int is_valid_ssa_node_blk(struct f2fs_sb_info *s= bi, u32 nid, =20 sum_entry =3D &(sum_blk->entries[offset]); =20 - if (le32_to_cpu(sum_entry->nid) !=3D nid) { + if (time_to_inject(FAULT_SUM_ENT) || + (le32_to_cpu(sum_entry->nid) !=3D nid)) { if (!c.fix_on || type < 0) { DBG(0, "nid [0x%x]\n", nid); DBG(0, "target blk_addr [0x%x]\n", blk_addr); @@ -282,7 +298,7 @@ static int is_valid_ssa_data_blk(struct f2fs_sb_info *s= bi, u32 blk_addr, struct f2fs_summary *sum_entry; struct seg_entry * se; u32 segno, offset; - int need_fix =3D 0, ret =3D 0; + int need_fix =3D 0, ret =3D 0, fault_sum_ent =3D 0; int type; =20 if (get_sb(feature) & F2FS_FEATURE_RO) @@ -293,7 +309,8 @@ static int is_valid_ssa_data_blk(struct f2fs_sb_info *s= bi, u32 blk_addr, =20 sum_blk =3D get_sum_block(sbi, segno, &type); =20 - if (type !=3D SEG_TYPE_DATA && type !=3D SEG_TYPE_CUR_DATA) { + if (time_to_inject(FAULT_SUM_TYPE) || + (type !=3D SEG_TYPE_DATA && type !=3D SEG_TYPE_CUR_DATA)) { /* can't fix current summary, then drop the block */ if (!c.fix_on || type < 0) { ASSERT_MSG("Summary footer is not for data segment"); @@ -314,7 +331,10 @@ static int is_valid_ssa_data_blk(struct f2fs_sb_info *= sbi, u32 blk_addr, =20 sum_entry =3D &(sum_blk->entries[offset]); =20 - if (le32_to_cpu(sum_entry->nid) !=3D parent_nid || + if (time_to_inject(FAULT_SUM_ENT)) + fault_sum_ent =3D 1; + + if (fault_sum_ent || le32_to_cpu(sum_entry->nid) !=3D parent_nid || sum_entry->version !=3D version || le16_to_cpu(sum_entry->ofs_in_node) !=3D idx_in_node) { if (!c.fix_on || type < 0) { @@ -333,7 +353,8 @@ static int is_valid_ssa_data_blk(struct f2fs_sb_info *s= bi, u32 blk_addr, DBG(0, "Target data block addr [0x%x]\n", blk_addr); ASSERT_MSG("Invalid data seg summary\n"); ret =3D -EINVAL; - } else if (is_valid_summary(sbi, sum_entry, blk_addr)) { + } else if (!fault_sum_ent && + is_valid_summary(sbi, sum_entry, blk_addr)) { /* delete wrong index */ ret =3D -EINVAL; } else { @@ -397,6 +418,9 @@ err: static int sanity_check_nat(struct f2fs_sb_info *sbi, u32 nid, struct node_info *ni) { + if (time_to_inject(FAULT_NAT)) + return -EINVAL; + if (!IS_VALID_NID(sbi, nid)) { ASSERT_MSG("nid is not valid. [0x%x]", nid); return -EINVAL; @@ -436,6 +460,9 @@ static int sanity_check_nid(struct f2fs_sb_info *sbi, u= 32 nid, struct f2fs_fsck *fsck =3D F2FS_FSCK(sbi); int ret; =20 + if (time_to_inject(FAULT_NODE)) + return -EINVAL; + ret =3D sanity_check_nat(sbi, nid, ni); if (ret) return ret; @@ -865,7 +892,7 @@ int chk_extended_attributes(struct f2fs_sb_info *sbi, u= 32 nid, "end of list", nid); need_fix =3D true; } - if (need_fix && c.fix_on) { + if ((time_to_inject(FAULT_XATTR_ENT) || need_fix) && c.fix_on) { memset(ent, 0, (u8 *)last_base_addr - (u8 *)ent); write_all_xattrs(sbi, inode, xattr_size, xattr); FIX_MSG("[0x%x] nullify wrong xattr entries", nid); @@ -907,7 +934,8 @@ void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 n= id, if (!compressed) goto check_next; =20 - if (!compr_supported || (node_blk->i.i_inline & F2FS_INLINE_DATA)) { + if (time_to_inject(FAULT_COMPR) || !compr_supported || + (node_blk->i.i_inline & F2FS_INLINE_DATA)) { /* * The 'compression' flag in i_flags affects the traverse of * the node tree. Thus, it must be fixed unconditionally @@ -943,12 +971,13 @@ check_next: f2fs_set_main_bitmap(sbi, ni->blk_addr, CURSEG_WARM_NODE); =20 - if (i_links =3D=3D 0 && (ftype =3D=3D F2FS_FT_CHRDEV || + if (time_to_inject(FAULT_INODE) || + (i_links =3D=3D 0 && (ftype =3D=3D F2FS_FT_CHRDEV || ftype =3D=3D F2FS_FT_BLKDEV || ftype =3D=3D F2FS_FT_FIFO || ftype =3D=3D F2FS_FT_SOCK || ftype =3D=3D F2FS_FT_SYMLINK || - ftype =3D=3D F2FS_FT_REG_FILE)) { + ftype =3D=3D F2FS_FT_REG_FILE))) { ASSERT_MSG("ino: 0x%x ftype: %d has i_links: %u", nid, ftype, i_links); if (c.fix_on) { @@ -1008,7 +1037,8 @@ check_next: if (c.feature & F2FS_FEATURE_EXTRA_ATTR) { unsigned int isize =3D le16_to_cpu(node_blk->i.i_extra_isize); - if (isize > 4 * DEF_ADDRS_PER_INODE) { + if (time_to_inject(FAULT_INODE) || + (isize > 4 * DEF_ADDRS_PER_INODE)) { ASSERT_MSG("[0x%x] wrong i_extra_isize=3D0x%x", nid, isize); if (c.fix_on) { @@ -1038,8 +1068,9 @@ check_next: unsigned int inline_size =3D le16_to_cpu(node_blk->i.i_inline_xattr_size); =20 - if (!inline_size || - inline_size > MAX_INLINE_XATTR_SIZE) { + if (time_to_inject(FAULT_INODE) || + (!inline_size || + inline_size > MAX_INLINE_XATTR_SIZE)) { ASSERT_MSG("[0x%x] wrong inline_xattr_size:%u", nid, inline_size); if (c.fix_on) { @@ -1056,9 +1087,10 @@ check_next: } ofs =3D get_extra_isize(node_blk); =20 - if ((node_blk->i.i_flags & cpu_to_le32(F2FS_CASEFOLD_FL)) && - (!S_ISDIR(le16_to_cpu(node_blk->i.i_mode)) || - !(c.feature & F2FS_FEATURE_CASEFOLD))) { + if (time_to_inject(FAULT_INODE) || + ((node_blk->i.i_flags & cpu_to_le32(F2FS_CASEFOLD_FL)) && + (!S_ISDIR(le16_to_cpu(node_blk->i.i_mode)) || + !(c.feature & F2FS_FEATURE_CASEFOLD)))) { ASSERT_MSG("[0x%x] unexpected casefold flag", nid); if (c.fix_on) { FIX_MSG("ino[0x%x] clear casefold flag", nid); @@ -1077,7 +1109,8 @@ check_next: qf_szchk_type[cur_qtype] =3D QF_SZCHK_INLINE; block_t blkaddr =3D le32_to_cpu(node_blk->i.i_addr[ofs]); =20 - if (blkaddr !=3D NULL_ADDR) { + if (time_to_inject(FAULT_INODE) || + (blkaddr !=3D NULL_ADDR)) { ASSERT_MSG("[0x%x] wrong inline reserve blkaddr:%u", nid, blkaddr); if (c.fix_on) { @@ -1088,7 +1121,8 @@ check_next: need_fix =3D 1; } } - if (i_size > inline_size) { + if (time_to_inject(FAULT_INODE) || + (i_size > inline_size)) { ASSERT_MSG("[0x%x] wrong inline size:%lu", nid, (unsigned long)i_size); if (c.fix_on) { @@ -1118,7 +1152,7 @@ check_next: block_t blkaddr =3D le32_to_cpu(node_blk->i.i_addr[ofs]); =20 DBG(3, "ino[0x%x] has inline dentry!\n", nid); - if (blkaddr !=3D 0) { + if (time_to_inject(FAULT_INODE) || (blkaddr !=3D 0)) { ASSERT_MSG("[0x%x] wrong inline reserve blkaddr:%u", nid, blkaddr); if (c.fix_on) { @@ -1728,6 +1762,9 @@ static int f2fs_check_hash_code(int encoding, int cas= efolded, struct f2fs_dir_entry *dentry, const unsigned char *name, u32 len, int enc_name) { + if (time_to_inject(FAULT_DENTRY)) + return 1; + /* Casefolded Encrypted names require a key to compute siphash */ if (enc_name && casefolded) return 0; @@ -1799,7 +1836,8 @@ static int __chk_dots_dentries(struct f2fs_sb_info *s= bi, int fixed =3D 0; =20 if ((name[0] =3D=3D '.' && len =3D=3D 1)) { - if (le32_to_cpu(dentry->ino) !=3D child->p_ino) { + if (time_to_inject(FAULT_DENTRY) || + (le32_to_cpu(dentry->ino) !=3D child->p_ino)) { ASSERT_MSG("Bad inode number[0x%x] for '.', parent_ino is [0x%x]\n", le32_to_cpu(dentry->ino), child->p_ino); dentry->ino =3D cpu_to_le32(child->p_ino); @@ -1809,13 +1847,16 @@ static int __chk_dots_dentries(struct f2fs_sb_info = *sbi, =20 if (name[0] =3D=3D '.' && name[1] =3D=3D '.' && len =3D=3D 2) { if (child->p_ino =3D=3D F2FS_ROOT_INO(sbi)) { - if (le32_to_cpu(dentry->ino) !=3D F2FS_ROOT_INO(sbi)) { + if (time_to_inject(FAULT_DENTRY) || + (le32_to_cpu(dentry->ino) !=3D + F2FS_ROOT_INO(sbi))) { ASSERT_MSG("Bad inode number[0x%x] for '..'\n", le32_to_cpu(dentry->ino)); dentry->ino =3D cpu_to_le32(F2FS_ROOT_INO(sbi)); fixed =3D 1; } - } else if (le32_to_cpu(dentry->ino) !=3D child->pp_ino) { + } else if (time_to_inject(FAULT_DENTRY) || + (le32_to_cpu(dentry->ino) !=3D child->pp_ino)) { ASSERT_MSG("Bad inode number[0x%x] for '..', parent parent ino is [0x%x= ]\n", le32_to_cpu(dentry->ino), child->pp_ino); dentry->ino =3D cpu_to_le32(child->pp_ino); @@ -1826,7 +1867,7 @@ static int __chk_dots_dentries(struct f2fs_sb_info *s= bi, if (f2fs_check_hash_code(get_encoding(sbi), casefolded, dentry, name, len= , enc_name)) fixed =3D 1; =20 - if (name[len] !=3D '\0') { + if (time_to_inject(FAULT_DENTRY) || (name[len] !=3D '\0')) { ASSERT_MSG("'.' is not NULL terminated\n"); name[len] =3D '\0'; memcpy(*filename, name, len); @@ -1889,7 +1930,8 @@ static int __chk_dentries(struct f2fs_sb_info *sbi, i= nt casefolded, i++; continue; } - if (!IS_VALID_NID(sbi, le32_to_cpu(dentry[i].ino))) { + if (time_to_inject(FAULT_DENTRY) || + !IS_VALID_NID(sbi, le32_to_cpu(dentry[i].ino))) { ASSERT_MSG("Bad dentry 0x%x with invalid NID/ino 0x%x", i, le32_to_cpu(dentry[i].ino)); if (c.fix_on) { @@ -1903,7 +1945,9 @@ static int __chk_dentries(struct f2fs_sb_info *sbi, i= nt casefolded, } =20 ftype =3D dentry[i].file_type; - if ((ftype <=3D F2FS_FT_UNKNOWN || ftype > F2FS_FT_LAST_FILE_TYPE)) { + if (time_to_inject(FAULT_DENTRY) || + (ftype <=3D F2FS_FT_UNKNOWN || + ftype > F2FS_FT_LAST_FILE_TYPE)) { ASSERT_MSG("Bad dentry 0x%x with unexpected ftype 0x%x", le32_to_cpu(dentry[i].ino), ftype); if (c.fix_on) { @@ -1918,7 +1962,8 @@ static int __chk_dentries(struct f2fs_sb_info *sbi, i= nt casefolded, =20 name_len =3D le16_to_cpu(dentry[i].name_len); =20 - if (name_len =3D=3D 0 || name_len > F2FS_NAME_LEN) { + if (time_to_inject(FAULT_DENTRY) || + (name_len =3D=3D 0 || name_len > F2FS_NAME_LEN)) { ASSERT_MSG("Bad dentry 0x%x with invalid name_len", i); if (c.fix_on) { FIX_MSG("Clear bad dentry 0x%x", i); @@ -2153,6 +2198,9 @@ int fsck_chk_data_blk(struct f2fs_sb_info *sbi, struc= t f2fs_inode *inode, return 0; } =20 + if (time_to_inject(FAULT_DATA)) + return -EINVAL; + if (!f2fs_is_valid_blkaddr(sbi, blk_addr, DATA_GENERIC)) { ASSERT_MSG("blkaddress is not valid. [0x%x]", blk_addr); return -EINVAL; @@ -3540,6 +3588,19 @@ int fsck_chk_curseg_info(struct f2fs_sb_info *sbi) return ret; } =20 +void print_fault_cnt(struct f2fs_fault_info *ffi) +{ + int i; + + printf("[Fault injection result]\n"); + for (i =3D 0; i < FAULT_MAX; i++) { + printf("%s: %u", f2fs_fault_name[i], ffi->fault_cnt[i]); + if (i < FAULT_MAX - 1) + printf(", "); + } + printf("\n"); +} + int fsck_verify(struct f2fs_sb_info *sbi) { unsigned int i =3D 0; @@ -3548,12 +3609,16 @@ int fsck_verify(struct f2fs_sb_info *sbi) u32 nr_unref_nid =3D 0; struct f2fs_fsck *fsck =3D F2FS_FSCK(sbi); struct hard_link_node *node =3D NULL; + struct f2fs_fault_info *ffi =3D &c.fault_info; bool verify_failed =3D false; uint64_t max_blks, data_secs, node_secs, free_blks; =20 if (c.show_file_map) return 0; =20 + if (ffi->inject_rate) + print_fault_cnt(ffi); + printf("\n"); =20 if (c.zoned_model =3D=3D F2FS_ZONED_HM) { diff --git a/fsck/main.c b/fsck/main.c index 47ba6c9..29792d8 100644 --- a/fsck/main.c +++ b/fsck/main.c @@ -91,6 +91,8 @@ void fsck_usage() MSG(0, " --no-kernel-check skips detecting kernel change\n"); MSG(0, " --kernel-check checks kernel change\n"); MSG(0, " --debug-cache to debug cache when -c is used\n"); + MSG(0, " --fault_injection=3D%%d to enable fault injection with specifie= d injection rate\n"); + MSG(0, " --fault_type=3D%%d to configure enabled fault injection type\n"= ); exit(1); } =20 @@ -263,6 +265,8 @@ void f2fs_parse_options(int argc, char *argv[]) {"no-kernel-check", no_argument, 0, 2}, {"kernel-check", no_argument, 0, 3}, {"debug-cache", no_argument, 0, 4}, + {"fault_injection", required_argument, 0, 5}, + {"fault_type", required_argument, 0, 6}, {0, 0, 0, 0} }; =20 @@ -287,6 +291,24 @@ void f2fs_parse_options(int argc, char *argv[]) case 4: c.cache_config.dbg_en =3D true; break; + case 5: + val =3D atoi(optarg); + if ((unsigned int)val <=3D 1) { + MSG(0, "\tError: injection rate must be larger " + "than 1: %d\n", val); + fsck_usage(); + } + c.fault_info.inject_rate =3D val; + c.fault_info.inject_type =3D F2FS_ALL_FAULT_TYPE; + break; + case 6: + val =3D atoi(optarg); + if (val >=3D (1UL << (FAULT_MAX))) { + MSG(0, "\tError: Invalid inject type: %x\n", val); + fsck_usage(); + } + c.fault_info.inject_type =3D val; + break; case 'a': c.auto_fix =3D 1; MSG(0, "Info: Automatic fix mode enabled.\n"); diff --git a/fsck/mkquota.c b/fsck/mkquota.c index 2451b58..eb63fc9 100644 --- a/fsck/mkquota.c +++ b/fsck/mkquota.c @@ -372,6 +372,9 @@ errcode_t quota_compare_and_update(struct f2fs_sb_info = *sbi, dict_t *dict =3D qctx->quota_dict[qtype]; errcode_t err =3D 0; =20 + if (time_to_inject(FAULT_QUOTA)) + return -EINVAL; + if (!dict) goto out; =20 diff --git a/include/f2fs_fs.h b/include/f2fs_fs.h index bb40adc..99bb3ed 100644 --- a/include/f2fs_fs.h +++ b/include/f2fs_fs.h @@ -29,6 +29,7 @@ #include #include #include +#include =20 #ifdef HAVE_CONFIG_H #include @@ -1476,6 +1477,34 @@ enum { F2FS_FEATURE_NAT_BITS =3D 0x0001, }; =20 +/* Fault inject control */ +enum { + FAULT_SEG_TYPE, + FAULT_SUM_TYPE, + FAULT_SUM_ENT, + FAULT_NAT, + FAULT_NODE, + FAULT_XATTR_ENT, + FAULT_COMPR, + FAULT_INODE, + FAULT_DENTRY, + FAULT_DATA, + FAULT_QUOTA, + FAULT_MAX +}; + +#define F2FS_ALL_FAULT_TYPE ((1UL << (FAULT_MAX)) - 1) + +struct f2fs_fault_info { + int inject_ops; + int inject_rate; + unsigned int inject_type; + unsigned int fault_cnt[FAULT_MAX]; +}; + +extern const char *f2fs_fault_name[FAULT_MAX]; +#define IS_FAULT_SET(fi, type) ((fi)->inject_type & (1UL << (type))) + struct f2fs_configuration { uint32_t conf_reserved_sections; uint32_t reserved_segments; @@ -1604,6 +1633,9 @@ struct f2fs_configuration { struct f2fs_journal nat_jnl; char nat_bytes[F2FS_MAX_BLKSIZE]; }; + + /* Fault injection control */ + struct f2fs_fault_info fault_info; }; =20 extern int utf8_to_utf16(char *, const char *, size_t, size_t); @@ -2131,4 +2163,30 @@ static inline void check_block_struct_sizes(void) + NR_DENTRY_IN_BLOCK * F2FS_SLOT_LEN * sizeof(u8) =3D=3D F2FS_BLKSIZE); } =20 +/* Fault inject control */ +#define time_to_inject(type) __time_to_inject(type, __func__, \ + __builtin_return_address(0)) +static inline bool __time_to_inject(int type, const char *func, + const char *parent_func) +{ + struct f2fs_fault_info *ffi =3D &c.fault_info; + + if (!ffi->inject_rate) + return false; + + if (!IS_FAULT_SET(ffi, type)) + return false; + + ffi->inject_ops++; + if (ffi->inject_ops >=3D ffi->inject_rate) { + ffi->inject_ops =3D 0; + if (ffi->fault_cnt[type] !=3D UINT_MAX) + ffi->fault_cnt[type]++; + MSG(0, "inject %s in %s of %p\n", + f2fs_fault_name[type], func, parent_func); + return true; + } + return false; +} + #endif /*__F2FS_FS_H */ diff --git a/man/fsck.f2fs.8 b/man/fsck.f2fs.8 index e39a846..8d9b0d9 100644 --- a/man/fsck.f2fs.8 +++ b/man/fsck.f2fs.8 @@ -67,6 +67,42 @@ Enable to show every directory entries in the partition. Specify the level of debugging options. The default number is 0, which shows basic debugging messages. .TP +.BI \-\-fault_injection=3D%d " enable fault injection" +Enable fault injection in all supported types with specified injection rat= e. +.TP +.BI \-\-fault_type=3D%d " configure fault injection type" +Support configuring fault injection type, should be enabled with +fault_injection option, fault type value is shown below, it supports +single or combined type. +.br +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +.br +Type_Name Type_Value +.br +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +.br +FAULT_SEG_TYPE 0x00000001 +.br +FAULT_SUM_TYPE 0x00000002 +.br +FAULT_SUM_ENT 0x00000004 +.br +FAULT_NAT 0x00000008 +.br +FAULT_NODE 0x00000010 +.br +FAULT_XATTR_ENT 0x00000020 +.br +FAULT_COMPR 0x00000040 +.br +FAULT_INODE 0x00000080 +.br +FAULT_DENTRY 0x00000100 +.br +FAULT_DATA 0x00000200 +.br +FAULT_QUOTA 0x00000400 +.TP .SH AUTHOR Initial checking code was written by Byoung Geun Kim . Jaegeuk Kim reworked most parts of the codes to suppo= rt --=20 2.49.0.901.g37484f566f-goog