| // Copyright 2021 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef THIRD_PARTY_F2FS_FSCK_H_ |
| #define THIRD_PARTY_F2FS_FSCK_H_ |
| |
| namespace f2fs::fsck { |
| |
| struct OrphanInfo { |
| uint32_t nr_inodes = 0; |
| uint32_t *ino_list = nullptr; |
| }; |
| |
| struct HardLinkNode { |
| uint32_t nid = 0; |
| uint32_t links = 0; |
| HardLinkNode *next = nullptr; |
| }; |
| |
| struct FsckInfo { |
| OrphanInfo orphani; |
| struct chk_result { |
| uint64_t valid_blk_cnt = 0; |
| uint32_t valid_nat_entry_cnt = 0; |
| uint32_t valid_node_cnt = 0; |
| uint32_t valid_inode_cnt = 0; |
| uint32_t multi_hard_link_files = 0; |
| uint64_t sit_valid_blocks = 0; |
| uint32_t sit_free_segs = 0; |
| } chk; |
| |
| HardLinkNode *hard_link_list_head = nullptr; |
| |
| char *main_seg_usage = nullptr; |
| char *main_area_bitmap = nullptr; |
| char *nat_area_bitmap = nullptr; |
| char *sit_area_bitmap = nullptr; |
| |
| uint64_t main_area_bitmap_sz = 0; |
| uint32_t nat_area_bitmap_sz = 0; |
| uint32_t sit_area_bitmap_sz = 0; |
| |
| uint64_t nr_main_blks = 0; |
| uint32_t nr_nat_entries = 0; |
| |
| uint32_t dentry_depth = 0; |
| }; |
| |
| enum class NodeType { |
| kTypeInode = 37, |
| kTypeDirectNode = 43, |
| kTypeIndirectNode = 53, |
| kTypeDoubleIndirectNode = 67 |
| }; |
| |
| enum class SegType { |
| kSegTypeData = 0, |
| kSegTypeCurData, |
| kSegTypeNode, |
| kSegTypeCurNode, |
| kSegTypeMax, |
| }; |
| |
| enum class FileType { |
| kFtUnknown = 0, |
| kFtRegFile, |
| kFtDir, |
| kFtChrdev, |
| kFtBlkdev, |
| kFtFifo, |
| kFtSock, |
| kFtSymlink, |
| kFtMax, |
| kFtOrphan |
| }; |
| |
| #if 0 // porting needed |
| struct DumpOption { |
| nid_t nid; |
| int start_sit; |
| int end_sit; |
| int start_ssa; |
| int end_ssa; |
| uint32_t blk_addr; |
| }; |
| #endif |
| |
| constexpr uint32_t kDefaultDirTreeLen = 256; |
| |
| class FsckWorker { |
| public: |
| // Not copyable or movable |
| FsckWorker() = delete; |
| FsckWorker(const FsckWorker &) = delete; |
| FsckWorker &operator=(const FsckWorker &) = delete; |
| FsckWorker(FsckWorker &&) = delete; |
| FsckWorker &operator=(FsckWorker &&) = delete; |
| FsckWorker(Bcache *bc) : bc_(bc), tree_mark_(kDefaultDirTreeLen) {} |
| |
| zx_status_t ChkNodeBlk(Inode *inode, uint32_t nid, FileType ftype, NodeType ntype, |
| uint32_t *blk_cnt); |
| zx_status_t ChkInodeBlk(uint32_t nid, FileType ftype, Node *node_blk, uint32_t *blk_cnt, |
| NodeInfo *ni); |
| zx_status_t ChkDataBlk(Inode *inode, uint32_t blk_addr, uint32_t *child_cnt, |
| uint32_t *child_files, int last_blk, FileType ftype, uint32_t parent_nid, |
| uint16_t idx_in_node, uint8_t ver); |
| void ChkDnodeBlk(Inode *inode, uint32_t nid, FileType ftype, Node *node_blk, uint32_t *blk_cnt, |
| NodeInfo *ni); |
| void ChkIdnodeBlk(Inode *inode, uint32_t nid, FileType ftype, Node *node_blk, uint32_t *blk_cnt); |
| void ChkDidnodeBlk(Inode *inode, uint32_t nid, FileType ftype, Node *node_blk, uint32_t *blk_cnt); |
| void ChkDentryBlk(Inode *inode, uint32_t blk_addr, uint32_t *child_cnt, uint32_t *child_files, |
| int last_blk); |
| |
| void PrintRawSbInfo(); |
| void PrintCkptInfo(); |
| void PrintNodeInfo(Node *node_block); |
| void PrintInodeInfo(Inode *inode); |
| void PrintDentry(uint32_t depth, std::string_view &name, DentryBlock *de_blk, int idx, |
| int last_blk); |
| |
| // Fsck checks f2fs consistency as below. |
| // 1. It loads a valid superblock, and it obtains valid node/inode/block count information. |
| zx_status_t DoMount(); |
| // 2. It builds three bitmap: |
| // a) main_area_bitmap indicates valid blocks that DoFsck() will identify. |
| // b) nat_area_bitmap indicates used NIDs retrieved from NAT. |
| // Once DoFsck() identifies a valid NID, it clears the bit. |
| // c) sit_area_bitmap indicates valid blocks retrieved from SIT. |
| // DoFsck() references it for checking the block validity. |
| zx_status_t Init(); |
| // 3. It checks orphan nodes, and it updates nat_area_bitmap. |
| void ChkOrphanNode(); |
| // 4. It traverses blocks from the root inode to leaf inodes to check the validity of |
| // the data/node blocks based on SSA and SIT and to update nat_area_bitmap and main_area_bitmap. |
| // In case of dir block, it checks the validity of child dentries and regarding inodes. |
| // It tracks various count information as well. |
| zx_status_t DoFsck(); |
| // 5. It determines the consistency: |
| // a) main_area_bitmap must be the same as sit_area_bitmap |
| // b) all bits in nat_area_bitmap must be clear. That is, no dangling NIDs. |
| // c) The count information that DoFsck() retrieves must be the same as that in 1. |
| // d) no unreachable links |
| zx_status_t Verify(); |
| void Free(); |
| void DoUmount(); |
| zx_status_t Run(); |
| zx_status_t ReadBlock(void *data, uint64_t bno); |
| |
| void InitSbInfo(); |
| void *ValidateCheckpoint(block_t cp_addr, uint64_t *version); |
| zx_status_t SanityCheckRawSuper(const SuperBlock *raw_super); |
| zx_status_t ValidateSuperblock(block_t block); |
| zx_status_t GetValidCheckpoint(); |
| zx_status_t SanityCheckCkpt(); |
| zx_status_t InitNodeManager(); |
| zx_status_t BuildNodeManager(); |
| zx_status_t BuildSitInfo(); |
| zx_status_t BuildCurseg(); |
| zx_status_t BuildSegmentManager(); |
| void BuildNatAreaBitmap(); |
| void BuildSitAreaBitmap(); |
| void BuildSitEntries(); |
| |
| zx_status_t ReadCompactedSummaries(); |
| zx_status_t ReadNormalSummaries(CursegType type); |
| zx_status_t RestoreNodeSummary(unsigned int segno, SummaryBlock *sum_blk); |
| SegType GetSumBlockInfo(uint32_t segno, SummaryBlock *sum_blk); |
| SegType GetSumEntry(uint32_t blk_addr, Summary *sum_entry); |
| void ResetCurseg(CursegType type, int modified); |
| zx_status_t RestoreCursegSummaries(); |
| SitBlock *GetCurrentSitPage(unsigned int segno); |
| void SegInfoFromRawSit(SegEntry *se, SitEntry *raw_sit); |
| void CheckBlockCount(uint32_t segno, SitEntry *raw_sit); |
| zx::status<int> LookupNatInJournal(uint32_t nid, RawNatEntry *raw_nat); |
| zx_status_t GetNatEntry(nid_t nid, RawNatEntry *raw_nat); |
| inline void ChkSegRange(unsigned int segno); |
| SegEntry *GetSegEntry(unsigned int segno); |
| uint32_t GetSegNo(uint32_t blk_addr); |
| zx_status_t GetNodeInfo(nid_t nid, NodeInfo *ni); |
| void AddIntoHardLinkList(uint32_t nid, uint32_t link_cnt); |
| zx_status_t FindAndDecHardLinkList(uint32_t nid); |
| |
| inline bool IsValidSsaNodeBlk(uint32_t nid, uint32_t blk_addr); |
| inline bool IsValidSsaDataBlk(uint32_t blk_addr, uint32_t parent_nid, uint16_t idx_in_node, |
| uint8_t version); |
| inline bool IsValidNid(uint32_t nid) { |
| ZX_ASSERT(nid <= (kNatEntryPerBlock * RawSuper(&sbi_)->segment_count_nat |
| << (sbi_.log_blocks_per_seg - 1))); |
| return true; |
| } |
| inline bool IsValidBlkAddr(uint32_t addr) { |
| if (addr >= RawSuper(&sbi_)->block_count || addr < GetSmInfo(&sbi_)->main_blkaddr) { |
| ZX_ASSERT_MSG(addr < RawSuper(&sbi_)->block_count, "block addr [0x%x]\n", addr); |
| ZX_ASSERT_MSG(addr >= GetSmInfo(&sbi_)->main_blkaddr, "block addr [0x%x]\n", addr); |
| } |
| return true; |
| } |
| |
| inline block_t StartSumBlock() { |
| return StartCpAddr(&sbi_) + LeToCpu(GetCheckpoint(&sbi_)->cp_pack_start_sum); |
| } |
| inline block_t SumBlkAddr(int base, int type) { |
| return StartCpAddr(&sbi_) + LeToCpu(GetCheckpoint(&sbi_)->cp_pack_total_block_count) - |
| (base + 1) + type; |
| } |
| inline void NodeInfoFromRawNat(NodeInfo *ni, RawNatEntry *raw_nat) { |
| ni->ino = LeToCpu(raw_nat->ino); |
| ni->blk_addr = LeToCpu(raw_nat->block_addr); |
| ni->version = raw_nat->version; |
| } |
| |
| #if 0 // porting needed |
| int FsckChkXattrBlk(uint32_t ino, uint32_t x_nid, uint32_t *blk_cnt); |
| void sit_dump(SbInfo *sbi, int start_sit, int end_sit); |
| void ssa_dump(SbInfo *sbi, int start_ssa, int end_ssa); |
| int dump_node(SbInfo *sbi, nid_t nid); |
| int dump_inode_from_blkaddr(SbInfo *sbi, uint32_t blk_addr); |
| #endif |
| |
| private: |
| FsckInfo fsck_; |
| SbInfo sbi_; |
| Bcache *bc_; |
| std::vector<char> tree_mark_; |
| }; |
| |
| zx_status_t Fsck(Bcache *bc); |
| |
| } // namespace f2fs::fsck |
| |
| #endif // THIRD_PARTY_F2FS_FSCK_H_ |