| // 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/inspect.h" |
| |
| #include "src/storage/f2fs/bcache.h" |
| #include "src/storage/f2fs/f2fs.h" |
| #include "src/storage/f2fs/superblock_info.h" |
| #include "src/storage/f2fs/vnode.h" |
| |
| namespace f2fs { |
| |
| InspectTree::InspectTree(F2fs* fs) : fs_(fs) { ZX_ASSERT(fs_ != nullptr); } |
| |
| void InspectTree::Initialize() { |
| zx::result<fs::FilesystemInfo> fs_info = fs_->GetFilesystemInfo(); |
| if (fs_info.is_error()) { |
| FX_LOGS(ERROR) << "Failed to initialize F2fs inspect tree: GetFilesystemInfo returned " |
| << fs_info.status_string(); |
| return; |
| } |
| |
| { |
| std::lock_guard guard(info_mutex_); |
| info_ = { |
| .id = fs_info.value().fs_id, |
| .type = fidl::ToUnderlying(fs_info.value().fs_type), |
| .name = fs_info.value().name, |
| .version_major = LeToCpu(fs_->GetSuperblockInfo().GetSuperblock().major_ver), |
| .version_minor = LeToCpu(fs_->GetSuperblockInfo().GetSuperblock().minor_ver), |
| .block_size = fs_info.value().block_size, |
| .max_filename_length = fs_info.value().max_filename_size, |
| }; |
| } |
| |
| { |
| std::lock_guard guard(usage_mutex_); |
| UpdateUsage(); |
| } |
| |
| { |
| std::lock_guard guard(fvm_mutex_); |
| UpdateFvmSizeInfo(); |
| } |
| |
| fs_inspect_nodes_ = fs_inspect::CreateTree(inspector_.GetRoot(), CreateCallbacks()); |
| inspector_.CreateStatsNode(); |
| } |
| |
| void InspectTree::UpdateUsage() { |
| zx::result<fs::FilesystemInfo> fs_info = fs_->GetFilesystemInfo(); |
| if (fs_info.is_error()) { |
| FX_LOGS(ERROR) << "Failed to initialize F2fs inspect tree: GetFilesystemInfo returned " |
| << fs_info.status_string(); |
| return; |
| } |
| |
| usage_.total_bytes = fs_info.value().total_bytes; |
| usage_.used_bytes = fs_info.value().used_bytes; |
| usage_.total_nodes = fs_info.value().total_nodes; |
| usage_.used_nodes = fs_info.value().used_nodes; |
| } |
| |
| void InspectTree::UpdateFvmSizeInfo() { |
| zx::result<fs_inspect::FvmData::SizeInfo> size_info = zx::ok(fs_inspect::FvmData::SizeInfo{ |
| .size_bytes = 0, .size_limit_bytes = 0, .available_space_bytes = 0}); |
| |
| { |
| fs_->GetBc().ForEachBcache([&size_info](Bcache* bc) { |
| if (size_info.is_error()) { |
| return; |
| } |
| |
| auto info = fs_inspect::FvmData::GetSizeInfoFromDevice(*bc->GetDevice()); |
| if (info.is_error()) { |
| size_info = info.take_error(); |
| return; |
| } |
| |
| size_info.value().size_bytes += info->size_bytes; |
| size_info.value().size_limit_bytes += info->size_limit_bytes; |
| size_info.value().available_space_bytes += info->available_space_bytes; |
| }); |
| |
| if (size_info.is_error()) { |
| FX_LOGS(WARNING) << "Failed to obtain size information from block device: " |
| << size_info.status_string(); |
| } |
| } |
| |
| if (size_info.is_ok()) { |
| fvm_.size_info = size_info.value(); |
| } |
| } |
| |
| void InspectTree::OnOutOfSpace() { |
| zx::time curr_time = zx::clock::get_monotonic(); |
| std::lock_guard guard(fvm_mutex_); |
| if ((curr_time - last_out_of_space_time_) > kOutOfSpaceDuration) { |
| ++fvm_.out_of_space_events; |
| last_out_of_space_time_ = curr_time; |
| } |
| } |
| |
| fs_inspect::NodeCallbacks InspectTree::CreateCallbacks() { |
| return { |
| .info_callback = |
| [this] { |
| std::lock_guard guard(info_mutex_); |
| return info_; |
| }, |
| .usage_callback = |
| [this] { |
| std::lock_guard guard(usage_mutex_); |
| UpdateUsage(); |
| return usage_; |
| }, |
| .fvm_callback = |
| [this] { |
| std::lock_guard guard(fvm_mutex_); |
| UpdateFvmSizeInfo(); |
| return fvm_; |
| }, |
| }; |
| } |
| |
| } // namespace f2fs |