blob: b7238d21e4cecab141a202d825b76cd1d6b056c9 [file] [log] [blame]
// 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 writeback_control *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 writeback_control *wbc);
int F2fsWriteNodePages(struct address_space *mapping, struct writeback_control *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 writeback_control *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_