| // Copyright 2017 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 <dirent.h> |
| #include <fcntl.h> |
| #include <fidl/fuchsia.device/cpp/wire.h> |
| #include <fidl/fuchsia.hardware.block.volume/cpp/wire.h> |
| #include <fidl/fuchsia.hardware.block/cpp/wire.h> |
| #include <fidl/fuchsia.hardware.ramdisk/cpp/wire.h> |
| #include <lib/component/incoming/cpp/protocol.h> |
| #include <lib/component/incoming/cpp/service.h> |
| #include <lib/device-watcher/cpp/device-watcher.h> |
| #include <lib/fdio/cpp/caller.h> |
| #include <lib/fdio/directory.h> |
| #include <lib/fdio/fd.h> |
| #include <lib/fdio/fdio.h> |
| #include <lib/fdio/namespace.h> |
| #include <lib/fdio/watcher.h> |
| #include <lib/fit/defer.h> |
| #include <lib/syslog/cpp/macros.h> |
| #include <lib/zbi-format/partition.h> |
| #include <lib/zx/channel.h> |
| #include <lib/zx/job.h> |
| #include <lib/zx/time.h> |
| #include <lib/zx/vmo.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| #include <zircon/process.h> |
| #include <zircon/processargs.h> |
| #include <zircon/status.h> |
| #include <zircon/syscalls.h> |
| #include <zircon/types.h> |
| |
| #include <memory> |
| #include <utility> |
| |
| #include <fbl/string.h> |
| #include <fbl/string_printf.h> |
| #include <fbl/unique_fd.h> |
| #include <ramdevice-client/ramdisk.h> |
| |
| constexpr char kRamctlDevPath[] = "/dev"; |
| constexpr char kRamctlPath[] = "sys/platform/ram-disk/ramctl"; |
| constexpr char kBlockExtension[] = "block"; |
| constexpr zx::duration kDeviceWaitTime = zx::sec(10); |
| |
| struct ramdisk_client { |
| public: |
| DISALLOW_COPY_ASSIGN_AND_MOVE(ramdisk_client); |
| |
| static zx_status_t Create(int dev_root_fd, std::string_view instance_name, zx::duration duration, |
| std::unique_ptr<ramdisk_client>* out) { |
| fbl::String ramdisk_path = fbl::String::Concat({kRamctlPath, "/", instance_name}); |
| fbl::String block_path = fbl::String::Concat({ramdisk_path, "/", kBlockExtension}); |
| fbl::String path; |
| fbl::unique_fd dirfd; |
| if (dev_root_fd > -1) { |
| dirfd.reset(dup(dev_root_fd)); |
| path = block_path; |
| } else { |
| dirfd.reset(open(kRamctlDevPath, O_RDONLY | O_DIRECTORY)); |
| path = fbl::String::Concat({kRamctlDevPath, "/", block_path}); |
| } |
| if (!dirfd) { |
| return ZX_ERR_BAD_STATE; |
| } |
| fdio_cpp::UnownedFdioCaller caller(dirfd); |
| |
| zx::result channel = |
| device_watcher::RecursiveWaitForFile(dirfd.get(), ramdisk_path.c_str(), duration); |
| if (channel.is_error()) { |
| return channel.status_value(); |
| } |
| fidl::ClientEnd ramdisk_interface = |
| fidl::ClientEnd<fuchsia_hardware_ramdisk::Ramdisk>(std::move(channel.value())); |
| |
| std::string controller_path = std::string(ramdisk_path.c_str()) + "/device_controller"; |
| zx::result ramdisk_controller = |
| device_watcher::RecursiveWaitForFile(dirfd.get(), controller_path.c_str(), duration); |
| if (ramdisk_controller.is_error()) { |
| return ramdisk_controller.error_value(); |
| } |
| fidl::ClientEnd ramdisk_controller_interface = |
| fidl::ClientEnd<fuchsia_device::Controller>(std::move(ramdisk_controller.value())); |
| |
| // If binding to the block interface fails, ensure we still try to tear down the |
| // ramdisk driver. |
| auto cleanup = fit::defer([&ramdisk_controller_interface]() { |
| ramdisk_client::DestroyByHandle(ramdisk_controller_interface); |
| }); |
| |
| channel = device_watcher::RecursiveWaitForFile(dirfd.get(), block_path.c_str(), duration); |
| if (channel.is_error()) { |
| return channel.error_value(); |
| } |
| |
| controller_path = std::string(block_path.c_str()) + "/device_controller"; |
| zx::result controller = |
| device_watcher::RecursiveWaitForFile(dirfd.get(), controller_path.c_str(), duration); |
| if (controller.is_error()) { |
| return controller.error_value(); |
| } |
| |
| cleanup.cancel(); |
| *out = std::unique_ptr<ramdisk_client>(new ramdisk_client( |
| std::move(dirfd), std::move(path), std::move(block_path), std::move(ramdisk_interface), |
| std::move(ramdisk_controller_interface), |
| fidl::ClientEnd<fuchsia_hardware_block::Block>{std::move(channel.value())}, |
| fidl::ClientEnd<fuchsia_device::Controller>(std::move(controller.value())))); |
| return ZX_OK; |
| } |
| |
| static zx_status_t CreateV2(fidl::ClientEnd<fuchsia_io::Directory> outgoing_directory, |
| zx::eventpair lifeline, std::unique_ptr<ramdisk_client>* out) { |
| auto [svc_dir, server] = fidl::Endpoints<fuchsia_io::Directory>::Create(); |
| if (zx_status_t status = fdio_open3_at(outgoing_directory.channel().get(), "svc", |
| uint64_t{fuchsia_io::wire::kPermReadable}, |
| server.TakeChannel().release()); |
| status != ZX_OK) |
| return status; |
| |
| zx::result ramdisk_interface = component::ConnectAt<fuchsia_hardware_ramdisk::Ramdisk>(svc_dir); |
| if (ramdisk_interface.is_error()) |
| return ramdisk_interface.status_value(); |
| |
| zx::result volume_interface = |
| component::ConnectAt<fuchsia_hardware_block_volume::Volume>(svc_dir); |
| if (volume_interface.is_error()) |
| return volume_interface.status_value(); |
| fidl::ClientEnd<fuchsia_hardware_block::Block> block_interface(volume_interface->TakeChannel()); |
| |
| // Bind the outgoing directory to the namespace. |
| static std::atomic<int> counter; |
| // This deliberately binds to the top-level because there is/was watcher code that only worked |
| // at the top-level of the local namespace (opening intermediate local directories is not |
| // supported). |
| std::string bind_path = "/ramdisk-" + std::to_string(counter++); |
| fdio_ns_t* ns; |
| if (zx_status_t status = fdio_ns_get_installed(&ns); status != ZX_OK) |
| return status; |
| if (zx_status_t status = |
| fdio_ns_bind(ns, bind_path.c_str(), outgoing_directory.TakeHandle().release()); |
| status != ZX_OK) |
| return status; |
| fbl::String ram_disk_path = bind_path + "/svc/fuchsia.hardware.block.volume.Volume"; |
| *out = std::unique_ptr<ramdisk_client>(new ramdisk_client( |
| std::move(bind_path), std::move(ram_disk_path), *std::move(ramdisk_interface), |
| std::move(block_interface), std::move(lifeline))); |
| return ZX_OK; |
| } |
| |
| zx_status_t Rebind() { |
| if (!block_controller_) |
| return ZX_ERR_NOT_SUPPORTED; |
| const fidl::WireResult result = fidl::WireCall(block_controller_)->Rebind({}); |
| if (!result.ok()) { |
| return result.status(); |
| } |
| const fit::result response = result.value(); |
| if (response.is_error()) { |
| return response.error_value(); |
| } |
| ramdisk_interface_.reset(); |
| |
| // Ramdisk paths have the form: /dev/.../ramctl/ramdisk-xxx/block. |
| // To rebind successfully, first, we rebind the "ramdisk-xxx" path, |
| // and then we wait for "block" to rebind. |
| char ramdisk_path[PATH_MAX]; |
| |
| // Wait for the "ramdisk-xxx" path to rebind. |
| { |
| const char* sep = strrchr(relative_path_.c_str(), '/'); |
| strlcpy(ramdisk_path, relative_path_.c_str(), sep - relative_path_.c_str() + 1); |
| zx::result channel = |
| device_watcher::RecursiveWaitForFile(dev_root_fd_.get(), ramdisk_path, kDeviceWaitTime); |
| if (channel.is_error()) { |
| return channel.error_value(); |
| } |
| ramdisk_interface_.channel() = std::move(channel.value()); |
| } |
| |
| // Wait for the "block" path to rebind. |
| strlcpy(ramdisk_path, relative_path_.c_str(), sizeof(ramdisk_path)); |
| zx::result channel = |
| device_watcher::RecursiveWaitForFile(dev_root_fd_.get(), ramdisk_path, kDeviceWaitTime); |
| if (channel.is_error()) { |
| return channel.error_value(); |
| } |
| block_interface_.channel() = std::move(channel.value()); |
| return ZX_OK; |
| } |
| |
| zx_status_t Destroy() { |
| if (!ramdisk_interface_) { |
| return ZX_ERR_BAD_STATE; |
| } |
| |
| if (ramdisk_controller_) { |
| if (zx_status_t status = DestroyByHandle(ramdisk_controller_); status != ZX_OK) { |
| return status; |
| } |
| } |
| |
| if (!bind_path_.empty()) { |
| fdio_ns_t* ns; |
| if (fdio_ns_get_installed(&ns) == ZX_OK) |
| fdio_ns_unbind(ns, bind_path_.c_str()); |
| bind_path_.clear(); |
| } |
| |
| block_interface_.reset(); |
| return ZX_OK; |
| } |
| |
| // Destroy all open handles to the ramdisk, while leaving the ramdisk itself attached. |
| // After calling this method, destroying this object will have no effect. |
| zx_status_t Forget() { |
| if (!ramdisk_interface_) { |
| return ZX_ERR_BAD_STATE; |
| } |
| |
| ramdisk_interface_.reset(); |
| block_interface_.reset(); |
| return ZX_OK; |
| } |
| |
| zx::result<fidl::ClientEnd<fuchsia_hardware_block::Block>> Connect() const { |
| if (block_controller_) { |
| auto channel = device_watcher::RecursiveWaitForFile(dev_root_fd_.get(), |
| relative_path_.c_str(), kDeviceWaitTime); |
| if (channel.is_error()) { |
| return channel.take_error(); |
| } |
| return zx::ok(fidl::ClientEnd<fuchsia_hardware_block::Block>(std::move(channel).value())); |
| } |
| return component::Connect<fuchsia_hardware_block::Block>(path()); |
| } |
| |
| fidl::UnownedClientEnd<fuchsia_device::Controller> controller_interface() const { |
| return ramdisk_controller_; |
| } |
| |
| fidl::UnownedClientEnd<fuchsia_hardware_ramdisk::Ramdisk> ramdisk_interface() const { |
| return ramdisk_interface_.borrow(); |
| } |
| |
| fidl::UnownedClientEnd<fuchsia_hardware_block::Block> block_interface() const { |
| return block_interface_.borrow(); |
| } |
| |
| fidl::UnownedClientEnd<fuchsia_device::Controller> block_controller_interface() const { |
| return block_controller_.borrow(); |
| } |
| |
| const fbl::String& path() const { return path_; } |
| |
| ~ramdisk_client() { Destroy(); } |
| |
| private: |
| ramdisk_client(fbl::unique_fd dev_root_fd, fbl::String path, fbl::String relative_path, |
| fidl::ClientEnd<fuchsia_hardware_ramdisk::Ramdisk> ramdisk_interface, |
| fidl::ClientEnd<fuchsia_device::Controller> ramdisk_controller, |
| fidl::ClientEnd<fuchsia_hardware_block::Block> block_interface, |
| fidl::ClientEnd<fuchsia_device::Controller> block_controller) |
| : dev_root_fd_(std::move(dev_root_fd)), |
| path_(std::move(path)), |
| relative_path_(std::move(relative_path)), |
| ramdisk_interface_(std::move(ramdisk_interface)), |
| ramdisk_controller_(std::move(ramdisk_controller)), |
| block_interface_(std::move(block_interface)), |
| block_controller_(std::move(block_controller)) {} |
| |
| ramdisk_client(std::string bind_path, fbl::String path, |
| fidl::ClientEnd<fuchsia_hardware_ramdisk::Ramdisk> ramdisk_interface, |
| fidl::ClientEnd<fuchsia_hardware_block::Block> block_interface, |
| zx::eventpair lifeline) |
| : path_(std::move(path)), |
| ramdisk_interface_(std::move(ramdisk_interface)), |
| block_interface_(std::move(block_interface)), |
| lifeline_(std::move(lifeline)), |
| bind_path_(std::move(bind_path)) {} |
| |
| static zx_status_t DestroyByHandle(fidl::ClientEnd<fuchsia_device::Controller>& ramdisk) { |
| const fidl::WireResult result = fidl::WireCall(ramdisk)->ScheduleUnbind(); |
| if (!result.ok()) { |
| return result.status(); |
| } |
| const fit::result response = result.value(); |
| if (response.is_error()) { |
| return response.error_value(); |
| } |
| return ZX_OK; |
| } |
| |
| const fbl::unique_fd dev_root_fd_; |
| // The fully qualified path. |
| const fbl::String path_; |
| // The path relative to dev_root_fd_. |
| const fbl::String relative_path_; |
| fidl::ClientEnd<fuchsia_hardware_ramdisk::Ramdisk> ramdisk_interface_; |
| fidl::ClientEnd<fuchsia_device::Controller> ramdisk_controller_; |
| fidl::ClientEnd<fuchsia_hardware_block::Block> block_interface_; |
| fidl::ClientEnd<fuchsia_device::Controller> block_controller_; |
| |
| // v2 only: |
| zx::eventpair lifeline_; |
| std::string bind_path_; |
| }; |
| |
| namespace { |
| zx::result<fidl::ClientEnd<fuchsia_hardware_ramdisk::RamdiskController>> open_ramctl( |
| int dev_root_fd) { |
| fbl::unique_fd dirfd; |
| if (dev_root_fd > -1) { |
| dirfd.reset(dup(dev_root_fd)); |
| } else { |
| dirfd.reset(open(kRamctlDevPath, O_RDONLY | O_DIRECTORY)); |
| } |
| if (!dirfd) { |
| return zx::error(ZX_ERR_BAD_STATE); |
| } |
| fdio_cpp::FdioCaller caller(std::move(dirfd)); |
| return component::ConnectAt<fuchsia_hardware_ramdisk::RamdiskController>(caller.directory(), |
| kRamctlPath); |
| } |
| |
| zx_status_t ramdisk_create_legacy(int dev_root_fd, uint64_t blk_size, uint64_t blk_count, |
| const uint8_t* type_guid, size_t guid_len, ramdisk_client** out) { |
| if (type_guid == nullptr || guid_len < ZBI_PARTITION_GUID_LEN) { |
| return ZX_ERR_INVALID_ARGS; |
| } |
| zx::result ramctl = open_ramctl(dev_root_fd); |
| if (ramctl.is_error()) { |
| return ramctl.status_value(); |
| } |
| |
| const fidl::WireResult wire_result = |
| fidl::WireCall(ramctl.value()) |
| ->Create(blk_size, blk_count, |
| fidl::ObjectView<fuchsia_hardware_ramdisk::wire::Guid>::FromExternal( |
| reinterpret_cast<fuchsia_hardware_ramdisk::wire::Guid*>( |
| const_cast<uint8_t*>(type_guid)))); |
| if (!wire_result.ok()) { |
| return wire_result.status(); |
| } |
| const fit::result result = wire_result.value(); |
| if (result.is_error()) { |
| return result.error_value(); |
| } |
| |
| std::unique_ptr<ramdisk_client> client; |
| if (zx_status_t status = |
| ramdisk_client::Create(dev_root_fd, result->name.get(), kDeviceWaitTime, &client); |
| status != ZX_OK) { |
| return status; |
| } |
| *out = client.release(); |
| return ZX_OK; |
| } |
| |
| zx_status_t ramdisk_create_legacy_with_vmo(int dev_root_fd, zx_handle_t raw_vmo, |
| uint64_t block_size, const uint8_t* type_guid, |
| size_t guid_len, ramdisk_client** out) { |
| if (type_guid == nullptr || guid_len < ZBI_PARTITION_GUID_LEN) { |
| return ZX_ERR_INVALID_ARGS; |
| } |
| zx::vmo vmo(raw_vmo); |
| zx::result ramctl = open_ramctl(dev_root_fd); |
| if (ramctl.is_error()) { |
| return ramctl.status_value(); |
| } |
| |
| const fidl::WireResult wire_result = |
| fidl::WireCall(ramctl.value()) |
| ->CreateFromVmoWithParams( |
| std::move(vmo), block_size, |
| fidl::ObjectView<fuchsia_hardware_ramdisk::wire::Guid>::FromExternal( |
| reinterpret_cast<fuchsia_hardware_ramdisk::wire::Guid*>( |
| const_cast<uint8_t*>(type_guid)))); |
| if (!wire_result.ok()) { |
| return wire_result.status(); |
| } |
| const fit::result result = wire_result.value(); |
| if (result.is_error()) { |
| return result.error_value(); |
| } |
| |
| std::unique_ptr<ramdisk_client> client; |
| if (zx_status_t status = |
| ramdisk_client::Create(dev_root_fd, result->name.get(), kDeviceWaitTime, &client); |
| status != ZX_OK) { |
| return status; |
| } |
| *out = client.release(); |
| return ZX_OK; |
| } |
| |
| } // namespace |
| |
| __EXPORT zx_handle_t ramdisk_get_block_interface(const ramdisk_client_t* client) { |
| return client->block_interface().channel()->get(); |
| } |
| |
| __EXPORT zx_handle_t ramdisk_get_block_controller_interface(const ramdisk_client_t* client) { |
| return client->block_controller_interface().channel()->get(); |
| } |
| |
| __EXPORT const char* ramdisk_get_path(const ramdisk_client_t* client) { |
| return client->path().c_str(); |
| } |
| |
| __EXPORT zx_status_t ramdisk_sleep_after(const ramdisk_client* client, uint64_t block_count) { |
| const fidl::WireResult result = |
| fidl::WireCall(client->ramdisk_interface())->SleepAfter(block_count); |
| if (!result.ok()) { |
| return result.status(); |
| } |
| return ZX_OK; |
| } |
| |
| __EXPORT zx_status_t ramdisk_wake(const ramdisk_client* client) { |
| const fidl::WireResult result = fidl::WireCall(client->ramdisk_interface())->Wake(); |
| if (!result.ok()) { |
| return result.status(); |
| } |
| return ZX_OK; |
| } |
| |
| __EXPORT zx_status_t ramdisk_set_flags(const ramdisk_client* client, uint32_t flags) { |
| const fidl::WireResult result = |
| fidl::WireCall(client->ramdisk_interface()) |
| ->SetFlags(static_cast<fuchsia_hardware_ramdisk::wire::RamdiskFlag>(flags)); |
| if (!result.ok()) { |
| return result.status(); |
| } |
| return ZX_OK; |
| } |
| |
| __EXPORT zx_status_t ramdisk_get_block_counts(const ramdisk_client* client, |
| ramdisk_block_write_counts_t* out_counts) { |
| static_assert(sizeof(ramdisk_block_write_counts_t) == |
| sizeof(fuchsia_hardware_ramdisk::wire::BlockWriteCounts), |
| "Cannot convert between C library / FIDL block counts"); |
| |
| const fidl::WireResult result = fidl::WireCall(client->ramdisk_interface())->GetBlockCounts(); |
| if (!result.ok()) { |
| return result.status(); |
| } |
| const fidl::WireResponse response = result.value(); |
| memcpy(out_counts, &response.counts, sizeof(ramdisk_block_write_counts_t)); |
| return ZX_OK; |
| } |
| |
| __EXPORT zx_status_t ramdisk_rebind(ramdisk_client_t* client) { return client->Rebind(); } |
| |
| __EXPORT zx_status_t ramdisk_destroy(ramdisk_client* client) { |
| zx_status_t status = client->Destroy(); |
| delete client; |
| return status; |
| } |
| |
| __EXPORT zx_status_t ramdisk_forget(ramdisk_client* client) { |
| zx_status_t status = client->Forget(); |
| delete client; |
| return status; |
| } |
| |
| __EXPORT zx_status_t ramdisk_create_with_options(const ramdisk_options* options, |
| ramdisk_client_t** out) { |
| zx::vmo vmo(options->vmo); |
| if (!options->v2) { |
| static constexpr uint8_t null_type_guid[16] = {0}; |
| const uint8_t* type_guid = options->type_guid ? options->type_guid : null_type_guid; |
| if (vmo.is_valid()) { |
| return ramdisk_create_legacy_with_vmo(options->devfs_root_fd, vmo.get(), options->block_size, |
| type_guid, 16, out); |
| } |
| return ramdisk_create_legacy(options->devfs_root_fd, options->block_size, options->block_count, |
| type_guid, 16, out); |
| } |
| fbl::unique_fd dir( |
| options->svc_root_fd > 0 |
| ? (openat(options->svc_root_fd, "fuchsia.hardware.ramdisk.Service", O_RDONLY)) |
| : open("/svc/fuchsia.hardware.ramdisk.Service", O_RDONLY)); |
| if (!dir) |
| return ZX_ERR_NOT_FOUND; |
| std::string instance_name; |
| zx_status_t status = fdio_watch_directory( |
| dir.get(), |
| [](int, int event, const char* name, void* cookie) { |
| if (event == WATCH_EVENT_ADD_FILE && strcmp(name, ".") != 0) { |
| *reinterpret_cast<std::string*>(cookie) = name; |
| return ZX_ERR_STOP; |
| } |
| return ZX_OK; |
| }, |
| ZX_TIME_INFINITE, &instance_name); |
| if (status != ZX_ERR_STOP) |
| return status == ZX_OK ? ZX_ERR_NOT_FOUND : status; |
| zx::result<fuchsia_hardware_ramdisk::Service::ServiceClient> service; |
| if (options->svc_root_fd > 0) { |
| fdio_cpp::UnownedFdioCaller caller(options->svc_root_fd); |
| service = component::OpenServiceAt<fuchsia_hardware_ramdisk::Service>(caller.directory(), |
| instance_name); |
| } else { |
| service = component::OpenService<fuchsia_hardware_ramdisk::Service>(instance_name); |
| } |
| if (service.is_error()) |
| return service.status_value(); |
| zx::result controller = service->connect_controller(); |
| if (controller.is_error()) |
| return controller.status_value(); |
| |
| fidl::Arena arena; |
| fuchsia_hardware_ramdisk::wire::Guid guid; |
| auto fidl_options = fuchsia_hardware_ramdisk::wire::Options::Builder(arena); |
| if (options->block_size > 0) |
| fidl_options.block_size(options->block_size); |
| if (options->block_count > 0) |
| fidl_options.block_count(options->block_count); |
| if (options->type_guid) { |
| memcpy(&guid.value.data_, options->type_guid, 16); |
| fidl_options.type_guid(guid); |
| ZX_ASSERT(fidl_options.has_type_guid()); |
| } |
| if (vmo.is_valid()) |
| fidl_options.vmo(std::move(vmo)); |
| fidl_options.publish(true); |
| const fidl::WireResult result = fidl::WireCall(*controller)->Create(fidl_options.Build()); |
| if (!result.ok()) |
| return result.status(); |
| fit::result response = result.value(); |
| if (response.is_error()) |
| return response.error_value(); |
| std::unique_ptr<ramdisk_client> client; |
| if (zx_status_t status = ramdisk_client::CreateV2(std::move(response->outgoing), |
| std::move(response->lifeline), &client); |
| status != ZX_OK) { |
| return status; |
| } |
| *out = client.release(); |
| return ZX_OK; |
| } |
| |
| namespace ramdevice_client { |
| |
| zx::result<Ramdisk> Ramdisk::Create(int block_size, uint64_t block_count, |
| std::optional<int> svc_root_fd, |
| const Ramdisk::Options& options) { |
| ramdisk_client_t* client; |
| ramdisk_options_t ramdisk_options{ |
| .block_size = static_cast<uint32_t>(block_size), |
| .block_count = block_count, |
| .type_guid = options.type_guid ? options.type_guid->data() : nullptr, |
| .v2 = true, |
| .svc_root_fd = svc_root_fd ? *svc_root_fd : -1, |
| }; |
| if (zx::result<> result = zx::make_result(ramdisk_create_with_options(&ramdisk_options, &client)); |
| result.is_error()) { |
| FX_LOGS(ERROR) << "Could not create ramdisk for test: " << result.status_string(); |
| return result.take_error(); |
| } |
| return zx::ok(Ramdisk(client)); |
| } |
| |
| zx::result<Ramdisk> Ramdisk::CreateLegacy(int block_size, uint64_t block_count, |
| std::optional<int> devfs_root_fd, |
| const Ramdisk::Options& options) { |
| ramdisk_client_t* client; |
| ramdisk_options_t ramdisk_options{ |
| .block_size = static_cast<uint32_t>(block_size), |
| .block_count = block_count, |
| .type_guid = options.type_guid ? options.type_guid->data() : nullptr, |
| .v2 = false, |
| .devfs_root_fd = devfs_root_fd ? *devfs_root_fd : -1, |
| }; |
| if (zx::result<> result = zx::make_result(ramdisk_create_with_options(&ramdisk_options, &client)); |
| result.is_error()) { |
| FX_LOGS(ERROR) << "Could not create ramdisk for test: " << result.status_string(); |
| return result.take_error(); |
| } |
| return zx::ok(Ramdisk(client)); |
| } |
| |
| zx::result<Ramdisk> Ramdisk::CreateWithVmo(zx::vmo vmo, uint64_t block_size, |
| std::optional<int> svc_root_fd, |
| const Ramdisk::Options& options) { |
| ramdisk_client_t* client; |
| ramdisk_options_t ramdisk_options{ |
| .block_size = static_cast<uint32_t>(block_size), |
| .type_guid = options.type_guid ? options.type_guid->data() : nullptr, |
| .vmo = vmo.release(), |
| .v2 = true, |
| .svc_root_fd = svc_root_fd ? *svc_root_fd : -1, |
| }; |
| if (zx::result result = zx::make_result(ramdisk_create_with_options(&ramdisk_options, &client)); |
| result.is_error()) { |
| FX_LOGS(ERROR) << "Could not create ramdisk for test: " << result.status_string(); |
| return result.take_error(); |
| } |
| return zx::ok(Ramdisk(client)); |
| } |
| |
| zx::result<Ramdisk> Ramdisk::CreateLegacyWithVmo(zx::vmo vmo, uint64_t block_size, |
| std::optional<int> devfs_root_fd, |
| const Ramdisk::Options& options) { |
| ramdisk_client_t* client; |
| ramdisk_options_t ramdisk_options{ |
| .block_size = static_cast<uint32_t>(block_size), |
| .type_guid = options.type_guid ? options.type_guid->data() : nullptr, |
| .vmo = vmo.release(), |
| .v2 = false, |
| .devfs_root_fd = devfs_root_fd ? *devfs_root_fd : -1, |
| }; |
| if (zx::result result = zx::make_result(ramdisk_create_with_options(&ramdisk_options, &client)); |
| result.is_error()) { |
| FX_LOGS(ERROR) << "Could not create ramdisk for test: " << result.status_string(); |
| return result.take_error(); |
| } |
| return zx::ok(Ramdisk(client)); |
| } |
| |
| zx::result<fidl::ClientEnd<fuchsia_hardware_block::Block>> Ramdisk::ConnectBlock() const { |
| return client_->Connect(); |
| } |
| |
| fidl::UnownedClientEnd<fuchsia_device::Controller> Ramdisk::LegacyController() const { |
| return client_->block_controller_interface(); |
| } |
| |
| } // namespace ramdevice_client |