// 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/f2fs.h"

namespace f2fs {

zx_vaddr_t VmoNode::PageIndexToAddress(pgoff_t page_index) {
  return safemath::CheckMul<zx_vaddr_t>(page_index, kPageSize).ValueOrDie();
}

pgoff_t VmoNode::AddressToPageIndex(zx_vaddr_t address) {
  return safemath::CheckDiv<pgoff_t>(address, kPageSize).ValueOrDie();
}

VmoNode::~VmoNode() {
  ZX_DEBUG_ASSERT(!active_pages_);
  if (address_) {
    zx::vmar::root_self()->unmap(address_, PageIndexToAddress(kVmoSize));
  }
  vmo_.reset();
}

zx::status<bool> VmoNode::CreateAndLockVmo(pgoff_t offset) {
  ZX_DEBUG_ASSERT(offset < kVmoSize);
  zx_vaddr_t vmo_size = PageIndexToAddress(kVmoSize);
  if (!vmo_.is_valid()) {
    if (zx_status_t status = vmo_.create(vmo_size, ZX_VMO_DISCARDABLE, &vmo_); status != ZX_OK) {
      return zx::error(status);
    }
    if (zx_status_t status = zx::vmar::root_self()->map(ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, vmo_,
                                                        0, vmo_size, &address_);
        status != ZX_OK) {
      vmo_.reset();
      return zx::error(status);
    }
  }

  if (!active_pages_) {
    zx_status_t status = vmo_.op_range(ZX_VMO_OP_TRY_LOCK, 0, vmo_size, nullptr, 0);
    if (status == ZX_ERR_UNAVAILABLE) {
      // When kernel has decommitted any Pages in |vmo_|, the corresponding bits in |page_bitmap_|
      // are cleared too.
      zx_vmo_lock_state_t lock_state;
      status = vmo_.op_range(ZX_VMO_OP_LOCK, 0, vmo_size, &lock_state, sizeof(lock_state));
      auto discarded_offset = AddressToPageIndex(lock_state.discarded_offset);
      auto end = offset + AddressToPageIndex(fbl::round_up(lock_state.discarded_size, kPageSize));
      for (; discarded_offset < end; ++discarded_offset) {
        page_bitmap_.set(discarded_offset, false);
      }
    }
    ZX_DEBUG_ASSERT(status == ZX_OK);
  }

  bool committed = page_bitmap_[offset];
  if (!committed) {
    page_bitmap_.set(offset, true);
  }
  ++active_pages_;
  return zx::ok(committed);
}

zx_status_t VmoNode::UnlockVmo(pgoff_t offset) {
  ZX_DEBUG_ASSERT(offset < kVmoSize);
  if (--active_pages_) {
    return ZX_OK;
  }
  return vmo_.op_range(ZX_VMO_OP_UNLOCK, 0, PageIndexToAddress(kVmoSize), nullptr, 0);
}

zx::status<zx_vaddr_t> VmoNode::GetAddress(pgoff_t offset) {
  ZX_DEBUG_ASSERT(offset < kVmoSize);
  if (!address_ || !vmo_.is_valid()) {
    return zx::error(ZX_ERR_UNAVAILABLE);
  }
  return zx::ok(safemath::CheckAdd<zx_vaddr_t>(address_, PageIndexToAddress(offset)).ValueOrDie());
}

zx::status<bool> VmoManager::CreateAndLockVmo(const pgoff_t index) __TA_EXCLUDES(tree_lock_) {
  std::lock_guard tree_lock(tree_lock_);
  auto vmo_node_or = GetVmoNodeUnsafe(GetVmoNodeKey(index));
  ZX_DEBUG_ASSERT(vmo_node_or.is_ok());
  return vmo_node_or.value()->CreateAndLockVmo(GetOffsetInVmoNode(index));
}

zx_status_t VmoManager::UnlockVmo(const pgoff_t index, const bool evict) {
  std::lock_guard tree_lock(tree_lock_);
  auto vmo_node_or = FindVmoNodeUnsafe(GetVmoNodeKey(index));
  if (vmo_node_or.is_ok()) {
    if (auto status = vmo_node_or.value()->UnlockVmo(GetOffsetInVmoNode(index)); status != ZX_OK) {
      return status;
    }
    if (evict && !vmo_node_or.value()->GetActivePages()) {
      __UNUSED auto evicted = vmo_tree_.erase(*vmo_node_or.value());
    }
  }
  return vmo_node_or.status_value();
}

zx::status<zx_vaddr_t> VmoManager::GetAddress(pgoff_t index) {
  fs::SharedLock tree_lock(tree_lock_);
  auto vmo_node_or = FindVmoNodeUnsafe(GetVmoNodeKey(index));
  if (vmo_node_or.is_ok()) {
    return vmo_node_or.value()->GetAddress(GetOffsetInVmoNode(index));
  }
  return zx::error(vmo_node_or.error_value());
}

void VmoManager::Reset(bool shutdown) {
  std::lock_guard tree_lock(tree_lock_);
  pgoff_t prev_key = std::numeric_limits<pgoff_t>::max();
  while (!vmo_tree_.is_empty()) {
    if (shutdown) {
      __UNUSED auto evicted = vmo_tree_.pop_front();
    } else {
      auto key = (prev_key < std::numeric_limits<pgoff_t>::max()) ? prev_key : 0;
      auto current = vmo_tree_.lower_bound(key);
      if (current == vmo_tree_.end()) {
        break;
      }
      // Unless the |prev_key| Page is evicted, try the next Page.
      if (prev_key == current->GetKey()) {
        ++current;
        if (current == vmo_tree_.end()) {
          break;
        }
      }

      prev_key = current->GetKey();
      if (!current->GetActivePages()) {
        __UNUSED auto evicted = vmo_tree_.erase(*current);
      }
    }
  }
}

zx::status<VmoNode *> VmoManager::FindVmoNodeUnsafe(const pgoff_t index) {
  if (auto vmo_node = vmo_tree_.find(index); vmo_node != vmo_tree_.end()) {
    return zx::ok(&(*vmo_node));
  }
  return zx::error(ZX_ERR_NOT_FOUND);
}

zx::status<VmoNode *> VmoManager::GetVmoNodeUnsafe(const pgoff_t index) {
  VmoNode *vmo_node = nullptr;
  if (auto vmo_node_or = FindVmoNodeUnsafe(index); vmo_node_or.is_error()) {
    auto new_node = std::make_unique<VmoNode>(index);
    vmo_node = new_node.get();
    vmo_tree_.insert(std::move(new_node));
  } else {
    vmo_node = vmo_node_or.value();
  }
  return zx::ok(vmo_node);
}

pgoff_t VmoManager::GetOffsetInVmoNode(pgoff_t page_index) { return page_index % kVmoSize; }

pgoff_t VmoManager::GetVmoNodeKey(pgoff_t page_index) {
  return page_index - GetOffsetInVmoNode(page_index);
}

}  // namespace f2fs
