1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <blobfs/fsck.h> 6#include <inttypes.h> 7 8#ifdef __Fuchsia__ 9#include <blobfs/blobfs.h> 10#else 11#include <blobfs/host.h> 12#endif 13 14//TODO(planders): Add more checks for fsck. 15namespace blobfs { 16 17void BlobfsChecker::TraverseInodeBitmap() { 18 for (unsigned n = 0; n < blobfs_->info_.inode_count; n++) { 19 blobfs_inode_t* inode = blobfs_->GetNode(n); 20 if (inode->start_block >= kStartBlockMinimum) { 21 alloc_inodes_++; 22 inode_blocks_ += static_cast<uint32_t>(inode->num_blocks); 23 24 size_t start_block = inode->start_block; 25 size_t end_block = inode->start_block + inode->num_blocks; 26 bool valid = true; 27 28 size_t first_unset = 0; 29 if (!blobfs_->block_map_.Get(start_block, end_block, &first_unset)) { 30 FS_TRACE_ERROR("check: ino %u using blocks [%zu, %zu). " 31 "Not fully allocated in block bitmap; first unset @%zu\n", 32 n, start_block, end_block, first_unset); 33 valid = false; 34 } 35 36 if (blobfs_->VerifyBlob(n) != ZX_OK) { 37 FS_TRACE_ERROR("check: detected inode %u with bad state\n", n); 38 valid = false; 39 } 40 if (!valid) { 41 error_blobs_++; 42 } 43 } 44 } 45} 46 47void BlobfsChecker::TraverseBlockBitmap() { 48 for (uint64_t n = 0; n < blobfs_->info_.block_count; n++) { 49 if (blobfs_->block_map_.Get(n, n + 1)) { 50 alloc_blocks_++; 51 } 52 } 53} 54 55zx_status_t BlobfsChecker::CheckAllocatedCounts() const { 56 zx_status_t status = ZX_OK; 57 if (alloc_blocks_ != blobfs_->info_.alloc_block_count) { 58 FS_TRACE_ERROR("check: incorrect allocated block count %" PRIu64 59 " (should be %u)\n", 60 blobfs_->info_.alloc_block_count, alloc_blocks_); 61 status = ZX_ERR_BAD_STATE; 62 } 63 64 if (alloc_blocks_ < kStartBlockMinimum) { 65 FS_TRACE_ERROR("check: allocated blocks (%u) are less than minimum%" PRIu64 "\n", 66 alloc_blocks_, kStartBlockMinimum); 67 status = ZX_ERR_BAD_STATE; 68 } 69 70 if (inode_blocks_ + kStartBlockMinimum != alloc_blocks_) { 71 FS_TRACE_ERROR("check: bitmap allocated blocks (%u) do not match inode allocated blocks " 72 "(%" PRIu64 ")\n", alloc_blocks_, inode_blocks_ + kStartBlockMinimum); 73 status = ZX_ERR_BAD_STATE; 74 } 75 76 if (alloc_inodes_ != blobfs_->info_.alloc_inode_count) { 77 FS_TRACE_ERROR("check: incorrect allocated inode count %" PRIu64 78 " (should be %u)\n", 79 blobfs_->info_.alloc_inode_count, alloc_inodes_); 80 status = ZX_ERR_BAD_STATE; 81 } 82 83 if (error_blobs_) { 84 status = ZX_ERR_BAD_STATE; 85 } 86 87 return status; 88} 89 90BlobfsChecker::BlobfsChecker() 91 : blobfs_(nullptr), alloc_inodes_(0), alloc_blocks_(0), error_blobs_(0), inode_blocks_(0) {}; 92 93void BlobfsChecker::Init(fbl::unique_ptr<Blobfs> blob) { 94 blobfs_ = fbl::move(blob); 95} 96 97zx_status_t blobfs_check(fbl::unique_ptr<Blobfs> blob) { 98 zx_status_t status = ZX_OK; 99 BlobfsChecker chk; 100 chk.Init(fbl::move(blob)); 101 chk.TraverseInodeBitmap(); 102 chk.TraverseBlockBitmap(); 103 status |= (status != ZX_OK) ? 0 : chk.CheckAllocatedCounts(); 104 return status; 105} 106 107} // namespace blobfs 108