| // Copyright 2020 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 "fs_block_client.h" |
| |
| #include "src/storage/blobfs/format.h" |
| |
| using block_client::BlockDevice; |
| |
| zx_status_t FsBlockClient::Create(std::unique_ptr<BlockDevice> device, |
| std::unique_ptr<FsBlockClient>* out) { |
| fuchsia_hardware_block_BlockInfo block_info; |
| zx_status_t status = device->BlockGetInfo(&block_info); |
| if (status != ZX_OK) { |
| return status; |
| } |
| |
| zx::vmo vmo; |
| status = zx::vmo::create(blobfs::kBlobfsBlockSize, 0, &vmo); |
| if (status != ZX_OK) { |
| return status; |
| } |
| |
| storage::Vmoid vmoid; |
| status = device->BlockAttachVmo(vmo, &vmoid); |
| if (status != ZX_OK) { |
| return status; |
| } |
| |
| out->reset(new FsBlockClient(std::move(device), block_info, std::move(vmo), std::move(vmoid))); |
| return ZX_OK; |
| } |
| |
| uint64_t FsBlockClient::BlockCount() const { |
| return block_info_.block_count / device_blocks_per_blobfs_block(); |
| } |
| |
| zx_status_t FsBlockClient::ReadBlock(uint64_t block, void* data) { |
| block_fifo_request_t request = {}; |
| request.opcode = BLOCKIO_READ; |
| request.vmoid = vmoid_.get(); |
| request.length = static_cast<uint32_t>(fs_block_to_device_block(1)); |
| request.vmo_offset = 0; |
| request.dev_offset = fs_block_to_device_block(block); |
| |
| zx_status_t status = device_->FifoTransaction(&request, 1); |
| if (status != ZX_OK) { |
| return status; |
| } |
| |
| return vmo_.read(data, 0, blobfs::kBlobfsBlockSize); |
| } |
| |
| zx_status_t FsBlockClient::WriteBlock(uint64_t block, const void* data) { |
| zx_status_t status = vmo_.write(data, 0, blobfs::kBlobfsBlockSize); |
| if (status != ZX_OK) { |
| return status; |
| } |
| |
| block_fifo_request_t request = {}; |
| request.opcode = BLOCKIO_WRITE; |
| request.vmoid = vmoid_.get(); |
| request.length = static_cast<uint32_t>(fs_block_to_device_block(1)); |
| request.vmo_offset = 0; |
| request.dev_offset = fs_block_to_device_block(block); |
| |
| return device_->FifoTransaction(&request, 1); |
| } |
| |
| FsBlockClient::FsBlockClient(std::unique_ptr<BlockDevice> device, |
| fuchsia_hardware_block_BlockInfo block_info, zx::vmo vmo, |
| storage::Vmoid vmoid) |
| : device_(std::move(device)), |
| block_info_(block_info), |
| vmo_(std::move(vmo)), |
| vmoid_(std::move(vmoid)) {} |
| |
| FsBlockClient::~FsBlockClient() { |
| zx_status_t status = device_->BlockDetachVmo(std::move(vmoid_)); |
| ZX_DEBUG_ASSERT(status == ZX_OK); |
| } |
| |
| uint64_t FsBlockClient::device_blocks_per_blobfs_block() const { |
| return blobfs::kBlobfsBlockSize / block_info_.block_size; |
| } |
| |
| uint64_t FsBlockClient::fs_block_to_device_block(uint64_t block) const { |
| return block * device_blocks_per_blobfs_block(); |
| } |