| // Copyright 2018 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/minfs/allocator/storage.h" |
| |
| #include <lib/syslog/cpp/macros.h> |
| |
| #include <cstdint> |
| #include <utility> |
| |
| #include "src/lib/storage/vfs/cpp/trace.h" |
| #include "src/storage/minfs/allocator/allocator.h" |
| #include "src/storage/minfs/format.h" |
| |
| namespace minfs { |
| |
| PersistentStorage::PersistentStorage(block_client::BlockDevice* device, SuperblockManager* sb, |
| size_t unit_size, GrowHandler grow_cb, |
| AllocatorMetadata metadata, uint32_t block_size) |
| : device_(device), |
| unit_size_(unit_size), |
| sb_(sb), |
| grow_cb_(std::move(grow_cb)), |
| metadata_(std::move(metadata)), |
| block_size_(block_size) {} |
| |
| zx::status<> PersistentStorage::AttachVmo(const zx::vmo& vmo, storage::OwnedVmoid* out) { |
| return zx::make_status(device_->BlockAttachVmo(vmo, &out->GetReference(device_))); |
| } |
| |
| zx::status<> PersistentStorage::Extend(PendingWork* write_transaction, WriteData data, |
| GrowMapCallback grow_map) { |
| TRACE_DURATION("minfs", "Minfs::PersistentStorage::Extend"); |
| ZX_DEBUG_ASSERT(write_transaction != nullptr); |
| if (!metadata_.UsingFvm()) { |
| FX_LOGS_FIRST_N(WARNING, 10) << "PersistentStorage::Extent can't extend on non-FVM devices."; |
| return zx::error(ZX_ERR_NO_SPACE); |
| } |
| uint32_t data_slices_diff = 1; |
| |
| // Determine if we will have enough space in the bitmap slice |
| // to grow |data_slices_diff| data slices. |
| |
| // How large is the bitmap right now? |
| uint32_t bitmap_slices = metadata_.Fvm().MetadataSlices(); |
| uint32_t bitmap_blocks = metadata_.Fvm().UnitsPerSlices(bitmap_slices, BlockSize()); |
| |
| // How large does the bitmap need to be? |
| uint32_t data_slices = metadata_.Fvm().DataSlices(); |
| uint32_t data_slices_new = data_slices + data_slices_diff; |
| |
| uint32_t pool_size = |
| metadata_.Fvm().UnitsPerSlices(data_slices_new, static_cast<uint32_t>(unit_size_)); |
| uint32_t bitmap_blocks_new = BitmapBlocksForSize(pool_size); |
| |
| if (bitmap_blocks_new > bitmap_blocks) { |
| // TODO(smklein): Grow the bitmap another slice. |
| // TODO(planders): Once we start growing the [block] bitmap, |
| // we will need to start growing the journal as well. |
| FX_LOGS(ERROR) << "Minfs allocator needs to increase bitmap size"; |
| return zx::error(ZX_ERR_NO_SPACE); |
| } |
| |
| // Make the request to the FVM. |
| extend_request_t request; |
| request.length = data_slices_diff; |
| request.offset = metadata_.Fvm().BlocksToSlices(metadata_.DataStartBlock()) + data_slices; |
| |
| zx_status_t status = device_->VolumeExtend(request.offset, request.length); |
| if (status != ZX_OK) { |
| FX_LOGS(WARNING) << "Failed to extend volume from " << data_slices << " slices to " |
| << data_slices_new << " slices, error " << status; |
| return zx::error(status); |
| } |
| |
| if (grow_cb_) { |
| if ((status = grow_cb_(pool_size)) != ZX_OK) { |
| FX_LOGS(ERROR) << "Allocator grow callback failure: " << status; |
| return zx::error(status); |
| } |
| } |
| |
| // Extend the in memory representation of our allocation pool -- it grew! |
| auto old_pool_size_or = grow_map(pool_size); |
| if (old_pool_size_or.is_error()) { |
| return old_pool_size_or.take_error(); |
| } |
| |
| metadata_.Fvm().SetDataSlices(data_slices_new); |
| metadata_.SetPoolTotal(pool_size); |
| sb_->Write(write_transaction, UpdateBackupSuperblock::kUpdate); |
| |
| // Update the block bitmap. |
| PersistRange(write_transaction, data, old_pool_size_or.value(), |
| pool_size - old_pool_size_or.value()); |
| return zx::ok(); |
| } |
| |
| } // namespace minfs |