| // 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 F2FS_NODE_H_ |
| #define F2FS_NODE_H_ |
| |
| namespace f2fs { |
| |
| /* start node id of a node block dedicated to the given node id */ |
| inline uint32_t StartNid(uint32_t nid) { |
| return (nid / kNatEntryPerBlock) * kNatEntryPerBlock; |
| } |
| |
| /* node block offset on the NAT area dedicated to the given start node id */ |
| //#define NAT_BLOCK_OFFSET(start_nid) (start_nid / kNatEntryPerBlock) |
| inline uint64_t NatBlockOffset(uint32_t start_nid) { |
| return start_nid / kNatEntryPerBlock; |
| } |
| |
| /* # of pages to perform readahead before building free nids */ |
| constexpr int kFreeNidPages = 4; |
| |
| /* maximum # of free node ids to produce during build_free_nids */ |
| constexpr int kMaxFreeNids = kNatEntryPerBlock * kFreeNidPages; |
| |
| /* maximum readahead size for node during getting data blocks */ |
| constexpr int kMaxRaNode = 128; |
| |
| /* maximum cached nat entries to manage memory footprint */ |
| constexpr uint32_t kNmWoutThreshold = 64 * kNatEntryPerBlock; |
| |
| /* vector size for gang look-up from nat cache that consists of radix tree */ |
| constexpr uint32_t kNatvecSize = 64; |
| |
| /* |
| * For node information |
| */ |
| struct NodeInfo { |
| nid_t nid = 0; /* node id */ |
| nid_t ino = 0; /* inode number of the node's owner */ |
| block_t blk_addr = 0; /* block address of the node */ |
| uint8_t version = 0; /* version of the node */ |
| }; |
| |
| struct NatEntry { |
| list_node_t list; /* for clean or dirty nat list */ |
| bool checkpointed = false; /* whether it is checkpointed or not */ |
| NodeInfo ni; /* in-memory node information */ |
| }; |
| |
| inline uint32_t NatGetNid(NatEntry *nat) { return nat->ni.nid; } |
| inline void NatSetNid(NatEntry *nat, nid_t n) { nat->ni.nid = n; } |
| inline block_t NatGetBlkaddr(NatEntry *nat) { return nat->ni.blk_addr; } |
| inline void NatSetBlkaddr(NatEntry *nat, block_t b) { nat->ni.blk_addr = b; } |
| inline uint32_t NatGetIno(NatEntry *nat) { return nat->ni.ino; } |
| inline void NatSetIno(NatEntry *nat, uint32_t i) { nat->ni.ino = i; } |
| inline uint8_t NatGetVersion(NatEntry *nat) { return nat->ni.version; } |
| inline void NatSetVersion(NatEntry *nat, uint8_t v) { nat->ni.version = v; } |
| |
| inline uint8_t IncNodeVersion(uint8_t version) { return ++version; } |
| |
| /* |
| * For free nid mangement |
| */ |
| enum class NidState { |
| kNidNew = 0, /* newly added to free nid list */ |
| kNidAlloc, /* it is allocated */ |
| }; |
| |
| struct FreeNid { |
| list_node_t list; /* for free node id list */ |
| nid_t nid = 0; /* node id */ |
| int state = 0; /* in use or not: kNidNew or kNidAlloc */ |
| }; |
| |
| class NodeMgr { |
| public: |
| // Not copyable or moveable |
| NodeMgr(const NodeMgr &) = delete; |
| NodeMgr &operator=(const NodeMgr &) = delete; |
| NodeMgr(NodeMgr &&) = delete; |
| NodeMgr &operator=(NodeMgr &&) = delete; |
| |
| // TODO: Implement constructor |
| NodeMgr(F2fs *fs); |
| |
| // TODO: Implement destructor |
| ~NodeMgr() = default; |
| |
| // Public functions |
| void SetFsyncMark(Page *page, int mark); |
| void SetDentryMark(Page *page, int mark); |
| |
| zx_status_t NextFreeNid(nid_t *nid); |
| void NodeInfoFromRawNat(NodeInfo *ni, RawNatEntry *raw_ne); |
| static zx_status_t RestoreNodeSummary(F2fs *fs, uint32_t segno, SummaryBlock *sum); |
| zx_status_t BuildNodeManager(); |
| void DestroyNodeManager(); |
| zx_status_t ReadNodePage(Page *page, nid_t nid, int type); |
| zx_status_t GetNodePage(pgoff_t nid, Page **out); |
| |
| zx_status_t GetDnodeOfData(DnodeOfData *dn, pgoff_t index, int ro); |
| |
| void FillNodeFooter(Page *page, nid_t nid, nid_t ino, uint32_t ofs, bool reset); |
| void CopyNodeFooter(Page *dst, Page *src); |
| |
| uint32_t OfsOfNode(Page *node_page); |
| |
| static int IsColdNode(Page *page); |
| static int IsColdFile(VnodeF2fs *vnode); |
| static int IsColdData(Page *page); |
| |
| uint8_t IsDentDnode(Page *page); |
| uint8_t IsFsyncDnode(Page *page); |
| |
| uint64_t CpverOfNode(Page *node_page); |
| |
| void FillNodeFooterBlkaddr(Page *page, block_t blkaddr); |
| static block_t NextBlkaddrOfNode(Page *node_page); |
| |
| nid_t InoOfNode(Page *node_page); |
| nid_t NidOfNode(Page *node_page); |
| |
| bool IS_DNODE(Page *node_page); |
| void GetNodeInfo(nid_t nid, NodeInfo *ni); |
| int SyncNodePages(nid_t ino, WritebackControl *wbc); |
| void SyncInodePage(DnodeOfData *dn); |
| |
| bool AllocNid(nid_t *nid); |
| void AllocNidFailed(nid_t nid); |
| void AllocNidDone(nid_t nid); |
| zx_status_t TruncateInodeBlocks(VnodeF2fs *vnode, pgoff_t from); |
| |
| zx_status_t RemoveInodePage(VnodeF2fs *vnode); |
| zx_status_t NewInodePage(Dir *parent, VnodeF2fs *child); |
| int IsCheckpointedNode(nid_t nid); |
| |
| void ClearColdData(Page *page); |
| |
| void DecValidNodeCount(SbInfo *sbis, VnodeF2fs *vnode, uint32_t count); |
| void GetNatBitmap(void *addr); |
| bool FlushNatsInJournal(); |
| void FlushNatEntries(); |
| |
| int F2fsWriteNodePage(Page *page, WritebackControl *wbc); |
| int F2fsWriteNodePages(struct address_space *mapping, WritebackControl *wbc); |
| zx_status_t RecoverInodePage(Page *page); |
| void RecoverNodePage(Page *page, Summary *sum, NodeInfo *ni, |
| block_t new_blkaddr); |
| |
| private: |
| F2fs *fs_; |
| |
| // Inline functions |
| bool inc_ValidNodeCount(SbInfo *sbi, VnodeF2fs *vnode, uint32_t count); |
| |
| pgoff_t CurrentNatAddr(nid_t start); |
| bool IsUpdatedNatPage(nid_t start); |
| pgoff_t NextNatAddr(pgoff_t block_addr); |
| void SetToNextNat(NmInfo *nm_i, nid_t start_nid); |
| |
| void SetNid(Page *p, int off, nid_t nid, bool i); |
| nid_t GetNid(Page *p, int off, bool i); |
| |
| #if 0 // porting needed |
| void SetColdData(Page *page); |
| #endif |
| |
| void SetColdNode(VnodeF2fs *vnode, Page *page); |
| |
| // Functions |
| void ClearNodePageDirty(Page *page); |
| Page *GetCurrentNatPage(nid_t nid); |
| Page *GetNextNatPage(nid_t nid); |
| void RaNatPages(nid_t nid); |
| NatEntry *LookupNatCache(NmInfo *nm_i, nid_t n); |
| uint32_t GangLookupNatCache(NmInfo *nm_i, nid_t start, uint32_t nr, |
| NatEntry **ep); |
| void DelFromNatCache(NmInfo *nm_i, NatEntry *e); |
| |
| NatEntry *GrabNatEntry(NmInfo *nm_i, nid_t nid); |
| void CacheNatEntry(NmInfo *nm_i, nid_t nid, RawNatEntry *ne); |
| void SetNodeAddr(NodeInfo *ni, block_t new_blkaddr); |
| int TryToFreeNats(int nr_shrink); |
| |
| int GetNodePath(long block, int offset[4], uint32_t noffset[4]); |
| void TruncateNode(DnodeOfData *dn); |
| zx_status_t TruncateDnode(DnodeOfData *dn); |
| zx_status_t TruncateNodes(DnodeOfData *dn, uint32_t nofs, int ofs, int depth); |
| zx_status_t TruncatePartialNodes(DnodeOfData *dn, Inode *ri, int *offset, int depth); |
| |
| zx_status_t NewNodePage(DnodeOfData *dn, uint32_t ofs, Page **out); |
| #if 0 // porting needed |
| void RaNodePage(nid_t nid); |
| #endif |
| Page *GetNodePageRa(Page *parent, int start); |
| |
| #if 0 // porting needed |
| int F2fsWriteNodePages(address_space *mapping, |
| WritebackControl *wbc); |
| int F2fsSetNodePageDirty(Page *page); |
| void F2fsInvalidateNodePage(Page *page, uint64_t offset); |
| int F2fsReleaseNodePage(Page *page, gfp_t wait); |
| #endif |
| |
| FreeNid *LookupFreeNidList(nid_t n, list_node_t *head); |
| void DelFromFreeNidList(FreeNid *i); |
| int AddFreeNid(NmInfo *nm_i, nid_t nid); |
| void RemoveFreeNid(NmInfo *nm_i, nid_t nid); |
| int ScanNatPage(NmInfo *nm_i, Page *nat_page, nid_t start_nid); |
| void BuildFreeNids(); |
| |
| zx_status_t InitNodeManager(); |
| zx_status_t CreateNodeManagerCaches(); |
| void DestroyNodeManagerCaches(); |
| }; |
| |
| } // namespace f2fs |
| |
| #endif // F2FS_NODE_H_ |