blob: 1ebc82bd50884845969353de3755bdf42ef1b16a [file] [log] [blame]
// Copyright 2023 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/bitmap.h"
#include <lib/syslog/cpp/macros.h>
#include "src/storage/f2fs/file_cache.h"
namespace f2fs {
size_t CountBits(const RawBitmap &bits, size_t offset, size_t len) {
if (offset >= bits.size())
return 0;
len = std::min(len, bits.size() - offset);
constexpr size_t kNumBits = kBitsPerByte * sizeof(uint64_t);
const uint64_t *raw_bits = static_cast<const uint64_t *>(bits.StorageUnsafe()->GetData());
uint64_t sum = 0;
uint64_t end = CheckedDivRoundUp(offset + len, kNumBits);
for (uint64_t i = offset / kNumBits; i < end; ++i) {
std::bitset<kNumBits> node{raw_bits[i]};
sum += node.count();
}
return sum;
}
PageBitmap::PageBitmap(void *bitmap, size_t size)
: bits_(static_cast<uint8_t *>(bitmap)), size_(size) {}
PageBitmap::PageBitmap(fbl::RefPtr<Page> page, void *bitmap, size_t size)
: page_(std::move(page)), bits_(static_cast<uint8_t *>(bitmap)), size_(size) {
ZX_DEBUG_ASSERT(bitmap >= page_->GetAddress());
ZX_DEBUG_ASSERT(static_cast<uint8_t *>(bitmap) + CheckedDivRoundUp<size_t>(size, kBitsPerByte) <=
&page_->GetAddress<uint8_t>()[page_->Size()]);
}
bool PageBitmap::Set(size_t pos) {
if (pos >= size_) {
return false;
}
uint8_t &node = GetNode(pos);
const uint8_t mask = GetMask(uint8_t(1U), pos & kLastNodeMask);
bool was_set = (node & mask) != 0;
node |= mask;
return was_set;
}
bool PageBitmap::Clear(size_t pos) {
if (pos >= size_) {
return false;
}
uint8_t &node = GetNode(pos);
const uint8_t mask = GetMask(uint8_t(1U), pos & kLastNodeMask);
bool was_set = (node & mask) != 0;
node &= ~mask;
return was_set;
}
bool PageBitmap::Test(size_t pos) const {
if (pos >= size_) {
return false;
}
return (GetNode(pos) & GetMask(uint8_t(1U), pos & kLastNodeMask)) != 0;
}
size_t PageBitmap::FindNextZeroBit(size_t pos, size_t max_pos) const {
max_pos = std::min(max_pos, size_);
size_t offset_in_iter = pos & kLastNodeMask;
while (pos < max_pos) {
const uint8_t mask = GetMask(uint8_t(0xFFU), offset_in_iter);
const uint8_t &node = GetNode(pos);
if ((node & mask) != mask) { // found
for (pos -= offset_in_iter; offset_in_iter < kBitsPerByte; ++offset_in_iter) {
if (!(node & GetMask(1U, offset_in_iter))) {
return std::min(pos + offset_in_iter, max_pos);
}
}
}
pos = pos + kBitsPerByte - offset_in_iter;
offset_in_iter = 0;
}
return max_pos;
}
size_t PageBitmap::FindNextBit(size_t pos, size_t max_pos) const {
max_pos = std::min(max_pos, size_);
size_t offset_in_iter = pos & kLastNodeMask;
while (pos < max_pos) {
const uint8_t &node = GetNode(pos);
if (node & GetMask(uint8_t(0xFFU), offset_in_iter)) { // found
for (pos -= offset_in_iter; offset_in_iter < kBitsPerByte; ++offset_in_iter) {
if (node & GetMask(1U, offset_in_iter)) {
return std::min(pos + offset_in_iter, max_pos);
}
}
}
pos += kBitsPerByte - offset_in_iter;
offset_in_iter = 0;
}
return max_pos;
}
size_t PageBitmap::GetSize() const { return size_; }
} // namespace f2fs