blob: 45e7eaaa1f3cfca822037d7a9453666a86aeb8a4 [file] [log] [blame]
// 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 "src/storage/minfs/lazy_reader.h"
namespace minfs {
zx::status<> LazyReader::Read(ByteRange range, ReaderInterface* reader) {
if (range.Length() == 0)
return zx::ok();
// Find the first block that isn't loaded.
const range::Range block_range = BytesToBlocks(range, reader->BlockSize());
uint64_t block = block_range.Start();
if (mapped_.GetOne(block)) {
mapped_.Find(false, block + 1, block_range.End(), 1, &block);
}
// Loop through all unloaded block ranges and enqueue reads for them.
while (block < block_range.End()) {
uint64_t end;
mapped_.Find(true, block + 1, block_range.End(), 1, &end);
auto status = EnumerateBlocks(BlockRange(block, end),
[&](BlockRange range) { return reader->Enqueue(range); });
if (status.is_error())
return status.take_error();
mapped_.Find(false, end + 1, block_range.End(), 1, &block);
}
// Issue and wait for the reads to complete.
if (auto status = reader->RunRequests(); status.is_error())
return status.take_error();
// Mark the whole range as loaded.
mapped_.Set(block_range.Start(), block_range.End());
return zx::ok();
}
void LazyReader::SetLoaded(BlockRange range, bool set) {
if (set) {
mapped_.Set(range.Start(), range.End());
} else {
mapped_.Clear(range.Start(), range.End());
}
}
zx::status<uint64_t> MappedFileReader::Enqueue(BlockRange range) {
zx::status<DeviceBlockRange> status = mapper_.Map(range);
if (status.is_error())
return status.take_error();
const DeviceBlockRange device_range = status.value();
if (device_range.IsMapped()) {
builder_.Add(
storage::Operation{
.type = storage::OperationType::kRead,
.vmo_offset = range.Start(),
.dev_offset = device_range.block(),
.length = device_range.count(),
},
&buffer_);
} else {
// This probably isn't necessary because the blocks should already be clean, but it's safe.
if (zx_status_t ret = buffer_.Zero(range.Start(), device_range.count()); ret != ZX_OK) {
return zx::error(ret);
}
}
return zx::ok(device_range.count());
}
} // namespace minfs