| // Copyright 2022 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. |
| |
| #include "src/storage/f2fs/node_page.h" |
| |
| #include "src/storage/f2fs/common.h" |
| #include "src/storage/f2fs/node.h" |
| |
| namespace f2fs { |
| void NodePage::FillNodeFooter(nid_t nid, nid_t ino, size_t ofs) { |
| NodeFooter &raw_footer = node().footer; |
| raw_footer.nid = CpuToLe(nid); |
| raw_footer.ino = CpuToLe(ino); |
| raw_footer.flag = CpuToLe( |
| safemath::checked_cast<uint32_t>(ofs << static_cast<uint32_t>(BitShift::kOffsetBitShift))); |
| } |
| |
| void NodePage::CopyNodeFooterFrom(NodePage &src) { |
| memcpy(&node().footer, &src.node().footer, sizeof(NodeFooter)); |
| } |
| |
| void NodePage::FillNodeFooterBlkaddr(block_t blkaddr, uint64_t ver) { |
| NodeFooter &raw_footer = node().footer; |
| raw_footer.cp_ver = CpuToLe(ver); |
| raw_footer.next_blkaddr = CpuToLe(blkaddr); |
| } |
| |
| nid_t NodePage::InoOfNode() const { return LeToCpu(node().footer.ino); } |
| |
| nid_t NodePage::NidOfNode() const { return LeToCpu(node().footer.nid); } |
| |
| uint32_t NodePage::OfsOfNode() const { |
| uint32_t flag = LeToCpu(node().footer.flag); |
| return flag >> static_cast<int>(BitShift::kOffsetBitShift); |
| } |
| |
| uint64_t NodePage::CpverOfNode() const { return LeToCpu(node().footer.cp_ver); } |
| |
| block_t NodePage::NextBlkaddrOfNode() const { return LeToCpu(node().footer.next_blkaddr); } |
| |
| // f2fs assigns the following node offsets described as (num). |
| // N = kNidsPerBlock |
| // |
| // Inode block (0) |
| // |- direct node (1) |
| // |- direct node (2) |
| // |- indirect node (3) |
| // | `- direct node (4 => 4 + N - 1) |
| // |- indirect node (4 + N) |
| // | `- direct node (5 + N => 5 + 2N - 1) |
| // `- double indirect node (5 + 2N) |
| // `- indirect node (6 + 2N) |
| // `- direct node (x(N + 1)) |
| bool NodePage::IsDnode() const { |
| uint32_t ofs = OfsOfNode(); |
| if (ofs == kOfsIndirectNode1 || ofs == kOfsIndirectNode2 || ofs == kOfsDoubleIndirectNode) { |
| return false; |
| } |
| if (ofs >= kOfsDoubleIndirectNode + 1) { |
| ofs -= kOfsDoubleIndirectNode + 1; |
| if (ofs % (kNidsPerBlock + 1)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| void NodePage::SetNid(size_t off, nid_t nid) { |
| if (IsInode()) { |
| node().i.i_nid[off - kNodeDir1Block] = CpuToLe(nid); |
| } else { |
| node().in.nid[off] = CpuToLe(nid); |
| } |
| } |
| |
| nid_t NodePage::GetNid(size_t off) const { |
| if (IsInode()) { |
| return LeToCpu(node().i.i_nid[off - kNodeDir1Block]); |
| } |
| return LeToCpu(node().in.nid[off]); |
| } |
| |
| bool NodePage::IsColdNode() const { |
| uint32_t flag = LeToCpu(node().footer.flag); |
| uint32_t bit = |
| safemath::CheckLsh(1U, static_cast<uint32_t>(BitShift::kColdBitShift)).ValueOrDie(); |
| return flag & bit; |
| } |
| |
| bool NodePage::IsFsyncDnode() const { |
| uint32_t flag = LeToCpu(node().footer.flag); |
| uint32_t bit = |
| safemath::CheckLsh(1U, static_cast<uint32_t>(BitShift::kFsyncBitShift)).ValueOrDie(); |
| return flag & bit; |
| } |
| |
| bool NodePage::IsDentDnode() const { |
| uint32_t flag = LeToCpu(node().footer.flag); |
| uint32_t bit = |
| safemath::CheckLsh(1U, static_cast<uint32_t>(BitShift::kDentBitShift)).ValueOrDie(); |
| return flag & bit; |
| } |
| |
| void NodePage::SetColdNode(const bool is_dir) { |
| Node &raw_node = node(); |
| uint32_t flag = LeToCpu(raw_node.footer.flag); |
| uint32_t bit = |
| safemath::CheckLsh(1U, static_cast<uint32_t>(BitShift::kColdBitShift)).ValueOrDie(); |
| if (is_dir) { |
| flag &= ~bit; |
| } else { |
| flag |= bit; |
| } |
| raw_node.footer.flag = CpuToLe(flag); |
| } |
| |
| void NodePage::SetFsyncMark(bool mark) { |
| Node &raw_node = node(); |
| uint32_t flag = LeToCpu(raw_node.footer.flag); |
| uint32_t bit = |
| safemath::CheckLsh(1U, static_cast<uint32_t>(BitShift::kFsyncBitShift)).ValueOrDie(); |
| if (mark) { |
| flag |= bit; |
| } else { |
| flag &= ~bit; |
| } |
| raw_node.footer.flag = CpuToLe(flag); |
| } |
| |
| void NodePage::SetDentryMark(bool mark) { |
| Node &raw_node = node(); |
| uint32_t flag = LeToCpu(raw_node.footer.flag); |
| uint32_t bit = |
| safemath::CheckLsh(1U, static_cast<uint32_t>(BitShift::kDentBitShift)).ValueOrDie(); |
| if (mark) { |
| flag |= bit; |
| } else { |
| flag &= ~bit; |
| } |
| raw_node.footer.flag = CpuToLe(flag); |
| } |
| |
| size_t NodePage::StartBidxOfNode(size_t num_addrs) const { |
| size_t node_ofs = OfsOfNode(), NumOfIndirectNodes = 0; |
| |
| if (node_ofs == kOfsInode) { |
| return 0; |
| } else if (node_ofs <= kOfsDirectNode2) { |
| NumOfIndirectNodes = 0; |
| } else if (node_ofs >= kOfsIndirectNode1 && node_ofs < kOfsIndirectNode2) { |
| NumOfIndirectNodes = 1; |
| } else if (node_ofs >= kOfsIndirectNode2 && node_ofs < kOfsDoubleIndirectNode) { |
| NumOfIndirectNodes = 2; |
| } else { |
| NumOfIndirectNodes = (node_ofs - kOfsDoubleIndirectNode - 2) / (kNidsPerBlock + 1); |
| } |
| |
| size_t bidx = node_ofs - NumOfIndirectNodes - 1; |
| return (num_addrs + safemath::CheckMul(bidx, kAddrsPerBlock)).ValueOrDie(); |
| } |
| |
| bool NodePage::IsInode() const { |
| NodeFooter &raw_footer = node().footer; |
| return raw_footer.nid == raw_footer.ino; |
| } |
| |
| block_t *NodePage::addrs_array() const { |
| Node &raw_node = node(); |
| if (IsInode()) { |
| Inode &inode = raw_node.i; |
| if (inode.i_inline & kExtraAttr) { |
| return inode.i_addr + (inode.i_extra_isize / sizeof(uint32_t)); |
| } |
| return inode.i_addr; |
| } |
| return raw_node.dn.addr; |
| } |
| |
| block_t NodePage::GetBlockAddr(const size_t offset) const { return LeToCpu(addrs_array()[offset]); } |
| |
| void NodePage::SetBlockAddr(const size_t offset, const block_t new_addr) const { |
| addrs_array()[offset] = CpuToLe(new_addr); |
| } |
| |
| void NodePage::SetDataBlkaddr(size_t ofs_in_node, block_t new_addr) { |
| ZX_DEBUG_ASSERT((new_addr == kNewAddr && GetBlockAddr(ofs_in_node) == kNullAddr) || |
| (new_addr != kNewAddr && GetBlockAddr(ofs_in_node) != kNullAddr)); |
| |
| SetBlockAddr(ofs_in_node, new_addr); |
| } |
| |
| } // namespace f2fs |