blob: 1fbd7620b2205c76b922a19c095fdc5c0f057944 [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/testing/fvm.h"
#include <fcntl.h>
#include <fidl/fuchsia.device/cpp/wire.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/device-watcher/cpp/device-watcher.h>
#include <lib/fdio/cpp/caller.h>
#include <lib/fdio/fdio.h>
#include <lib/syslog/cpp/macros.h>
#include <fbl/unique_fd.h>
#include <ramdevice-client/ramdisk.h>
#include "src/storage/lib/fs_management/cpp/fvm.h"
namespace storage {
constexpr uuid::Uuid kTestPartGUID = {0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
constexpr uuid::Uuid kTestUniqueGUID = {0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
zx::result<> BindFvm(fidl::UnownedClientEnd<fuchsia_device::Controller> device) {
auto resp = fidl::WireCall(device)->Bind("fvm.cm");
auto status = zx::make_result(resp.status());
if (status.is_ok()) {
if (resp->is_error()) {
status = zx::make_result(resp->error_value());
}
}
if (status.is_error()) {
FX_LOGS(ERROR) << "Could not bind disk to FVM driver: " << status.status_string();
return status.take_error();
}
return zx::ok();
}
zx::result<std::string> CreateFvmInstance(const std::string& device_path, size_t slice_size) {
zx::result device = component::Connect<fuchsia_hardware_block::Block>(device_path);
if (device.is_error()) {
return device.take_error();
}
if (zx::result status = zx::make_result(fs_management::FvmInit(device.value(), slice_size));
status.is_error()) {
FX_LOGS(ERROR) << "Could not format disk with FVM";
return status.take_error();
}
std::string controller_path = device_path + "/device_controller";
zx::result controller = component::Connect<fuchsia_device::Controller>(controller_path);
if (controller.is_error()) {
return controller.take_error();
}
if (zx::result status = BindFvm(controller.value()); status.is_error()) {
return status.take_error();
}
std::string fvm_disk_path = device_path + "/fvm";
if (zx::result channel = device_watcher::RecursiveWaitForFile(fvm_disk_path.c_str(), zx::sec(3));
channel.is_error()) {
FX_PLOGS(ERROR, channel.error_value()) << "FVM driver never appeared at " << fvm_disk_path;
return channel.take_error();
}
return zx::ok(fvm_disk_path);
}
zx::result<std::string> CreateFvmPartition(const std::string& device_path, size_t slice_size,
const FvmOptions& options) {
// Format the raw device to support FVM, and bind the FVM driver to it.
zx::result<std::string> fvm_disk_path = CreateFvmInstance(device_path, slice_size);
if (fvm_disk_path.is_error()) {
return fvm_disk_path.take_error();
}
// Open "fvm" driver
zx::result fvm_client_end =
component::Connect<fuchsia_hardware_block_volume::VolumeManager>(*fvm_disk_path);
if (fvm_client_end.is_error()) {
FX_LOGS(ERROR) << "Could not open FVM driver: " << fvm_client_end.status_string();
return fvm_client_end.take_error();
}
uint64_t slice_count = options.initial_fvm_slice_count;
uuid::Uuid type_guid = kTestPartGUID;
if (options.type) {
type_guid = uuid::Uuid(options.type->data());
}
zx::result controller = fs_management::FvmAllocatePartition(
*fvm_client_end, slice_count, type_guid, kTestUniqueGUID, options.name, 0);
if (controller.is_error()) {
FX_LOGS(ERROR) << "Could not allocate FVM partition (slice count: "
<< options.initial_fvm_slice_count << "): " << controller.status_string();
return controller.take_error();
}
fidl::WireResult result = fidl::WireCall(*controller)->GetTopologicalPath();
if (!result.ok()) {
FX_LOGS(ERROR) << "Could not get topological path of fvm partition (fidl error): "
<< result.FormatDescription();
return zx::error(result.status());
}
fit::result response = *result;
if (response.is_error()) {
FX_LOGS(ERROR) << "Could not get topological path of fvm partition: "
<< zx_status_get_string(response.error_value());
return zx::error(response.error_value());
}
return zx::ok(std::string(response->path.data(), response->path.size()));
}
} // namespace storage