| // 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_ |
| |
| #include "zircon/types.h" |
| namespace f2fs { |
| |
| /* start node id of a node block dedicated to the given node id */ |
| #define START_NID(nid) ((nid / NAT_ENTRY_PER_BLOCK) * NAT_ENTRY_PER_BLOCK) |
| |
| /* node block offset on the NAT area dedicated to the given start node id */ |
| #define NAT_BLOCK_OFFSET(start_nid) (start_nid / NAT_ENTRY_PER_BLOCK) |
| |
| /* # of pages to perform readahead before building free nids */ |
| #define FREE_NID_PAGES 4 |
| |
| /* maximum # of free node ids to produce during build_free_nids */ |
| #define MAX_FREE_NIDS (NAT_ENTRY_PER_BLOCK * FREE_NID_PAGES) |
| |
| /* maximum readahead size for node during getting data blocks */ |
| #define MAX_RA_NODE 128 |
| |
| /* maximum cached nat entries to manage memory footprint */ |
| #define NM_WOUT_THRESHOLD (64 * NAT_ENTRY_PER_BLOCK) |
| |
| /* vector size for gang look-up from nat cache that consists of radix tree */ |
| #define NATVEC_SIZE 64 |
| |
| /* |
| * For node information |
| */ |
| struct node_info { |
| nid_t nid; /* node id */ |
| nid_t ino; /* inode number of the node's owner */ |
| block_t blk_addr; /* block address of the node */ |
| unsigned char version; /* version of the node */ |
| }; |
| |
| struct nat_entry { |
| list_node_t list; /* for clean or dirty nat list */ |
| bool checkpointed; /* whether it is checkpointed or not */ |
| struct node_info ni; /* in-memory node information */ |
| }; |
| |
| #define nat_get_nid(nat) (nat->ni.nid) |
| #define nat_set_nid(nat, n) (nat->ni.nid = n) |
| #define nat_get_blkaddr(nat) (nat->ni.blk_addr) |
| #define nat_set_blkaddr(nat, b) (nat->ni.blk_addr = b) |
| #define nat_get_ino(nat) (nat->ni.ino) |
| #define nat_set_ino(nat, i) (nat->ni.ino = i) |
| #define nat_get_version(nat) (nat->ni.version) |
| #define nat_set_version(nat, v) (nat->ni.version = v) |
| |
| #define inc_node_version(version) (++version) |
| |
| /* |
| * For free nid mangement |
| */ |
| enum nid_state { |
| NID_NEW, /* newly added to free nid list */ |
| NID_ALLOC /* it is allocated */ |
| }; |
| |
| struct free_nid { |
| list_node_t list; /* for free node id list */ |
| nid_t nid; /* node id */ |
| int state; /* in use or not: NID_NEW or NID_ALLOC */ |
| }; |
| |
| 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(node_info *ni, f2fs_nat_entry *raw_ne); |
| static int RestoreNodeSummary(F2fs *fs, unsigned int segno, struct f2fs_summary_block *sum); |
| zx_status_t BuildNodeManager(); |
| void DestroyNodeManager(); |
| zx_status_t ReadNodePage(Page *page, unsigned long nid, int type); |
| zx_status_t GetNodePage(pgoff_t nid, Page **out); |
| |
| zx_status_t GetDnodeOfData(struct dnode_of_data *dn, pgoff_t index, int ro); |
| |
| void FillNodeFooter(Page *page, nid_t nid, nid_t ino, unsigned int ofs, bool reset); |
| void CopyNodeFooter(Page *dst, Page *src); |
| |
| unsigned int OfsOfNode(Page *node_page); |
| |
| static int IsColdNode(Page *page); |
| static int IsColdFile(VnodeF2fs *vnode); |
| static int IsColdData(Page *page); |
| |
| unsigned char IsDentDnode(Page *page); |
| unsigned char IsFsyncDnode(Page *page); |
| |
| unsigned long long 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, struct node_info *ni); |
| int SyncNodePages(nid_t ino, struct WritebackControl *wbc); |
| void SyncInodePage(struct dnode_of_data *dn); |
| |
| bool AllocNid(nid_t *nid); |
| void AllocNidFailed(nid_t nid); |
| void AllocNidDone(nid_t nid); |
| int TruncateInodeBlocks(VnodeF2fs *vnode, pgoff_t from); |
| |
| int RemoveInodePage(VnodeF2fs *vnode); |
| zx_status_t NewInodePage(Dir *parent, VnodeF2fs *child); |
| int IsCheckpointedNode(nid_t nid); |
| |
| void ClearColdData(Page *page); |
| |
| void DecValidNodeCount(struct f2fs_sb_info *sbi, VnodeF2fs *vnode, unsigned int count); |
| void GetNatBitmap(void *addr); |
| bool FlushNatsInJournal(); |
| void FlushNatEntries(); |
| |
| int F2fsWriteNodePage(Page *page, struct WritebackControl *wbc); |
| int F2fsWriteNodePages(struct address_space *mapping, struct WritebackControl *wbc); |
| zx_status_t RecoverInodePage(Page *page); |
| void RecoverNodePage(Page *page, struct f2fs_summary *sum, struct node_info *ni, |
| block_t new_blkaddr); |
| |
| private: |
| F2fs *fs_; |
| |
| // Inline functions |
| bool inc_valid_node_count(struct f2fs_sb_info *sbi, VnodeF2fs *vnode, unsigned int count); |
| |
| pgoff_t CurrentNatAddr(nid_t start); |
| bool IsUpdatedNatPage(nid_t start); |
| pgoff_t NextNatAddr(pgoff_t block_addr); |
| void SetToNextNat(struct f2fs_nm_info *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); |
| struct nat_entry *__LookupNatCache(struct f2fs_nm_info *nm_i, nid_t n); |
| unsigned int __GangLookupNatCache(struct f2fs_nm_info *nm_i, nid_t start, unsigned int nr, |
| struct nat_entry **ep); |
| void __DelFromNatCache(struct f2fs_nm_info *nm_i, struct nat_entry *e); |
| |
| struct nat_entry *GrabNatEntry(struct f2fs_nm_info *nm_i, nid_t nid); |
| void CacheNatEntry(struct f2fs_nm_info *nm_i, nid_t nid, struct f2fs_nat_entry *ne); |
| void SetNodeAddr(struct node_info *ni, block_t new_blkaddr); |
| int TryToFreeNats(int nr_shrink); |
| |
| int GetNodePath(long block, int offset[4], unsigned int noffset[4]); |
| void TruncateNode(struct dnode_of_data *dn); |
| int TruncateDnode(struct dnode_of_data *dn); |
| int TruncateNodes(struct dnode_of_data *dn, unsigned int nofs, int ofs, int depth); |
| int TruncatePartialNodes(struct dnode_of_data *dn, struct f2fs_inode *ri, int *offset, int depth); |
| |
| zx_status_t NewNodePage(struct dnode_of_data *dn, unsigned int 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(struct address_space *mapping, |
| struct WritebackControl *wbc); |
| int F2fsSetNodePageDirty(Page *page); |
| void F2fsInvalidateNodePage(Page *page, unsigned long offset); |
| int F2fsReleaseNodePage(Page *page, gfp_t wait); |
| #endif |
| |
| struct free_nid *__LookupFreeNidList(nid_t n, list_node_t *head); |
| void __DelFromFreeNidList(struct free_nid *i); |
| int AddFreeNid(struct f2fs_nm_info *nm_i, nid_t nid); |
| void RemoveFreeNid(struct f2fs_nm_info *nm_i, nid_t nid); |
| int ScanNatPage(struct f2fs_nm_info *nm_i, Page *nat_page, nid_t start_nid); |
| void BuildFreeNids(); |
| |
| zx_status_t InitNodeManager(); |
| int CreateNodeManagerCaches(); |
| void DestroyNodeManagerCaches(); |
| }; |
| |
| } // namespace f2fs |
| |
| #endif // F2FS_NODE_H_ |