| // Copyright 2022 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/runner.h" |
| |
| #include "src/storage/minfs/minfs_private.h" |
| |
| #ifdef __Fuchsia__ |
| #include <lib/syslog/cpp/macros.h> |
| |
| #include "src/storage/lib/vfs/cpp/pseudo_dir.h" |
| #include "src/storage/minfs/service/admin.h" |
| #endif |
| |
| namespace minfs { |
| |
| zx::result<std::unique_ptr<Runner>> Runner::Create(FuchsiaDispatcher dispatcher, |
| std::unique_ptr<Bcache> bc, |
| const MountOptions& options) { |
| std::unique_ptr<Runner> runner(new Runner(dispatcher)); |
| |
| auto minfs = Minfs::Create(dispatcher, std::move(bc), options, runner.get()); |
| if (minfs.is_error()) { |
| return minfs.take_error(); |
| } |
| |
| runner->minfs_ = *std::move(minfs); |
| runner->SetReadonly(options.writability != Writability::Writable); |
| |
| return zx::ok(std::move(runner)); |
| } |
| |
| std::unique_ptr<Bcache> Runner::Destroy(std::unique_ptr<Runner> runner) { |
| return Minfs::Destroy(std::move(runner->minfs_)); |
| } |
| |
| #ifdef __Fuchsia__ |
| Runner::Runner(async_dispatcher_t* dispatcher) |
| : fs::ManagedVfs(dispatcher), dispatcher_(dispatcher) {} |
| #else |
| Runner::Runner(std::nullptr_t dispatcher) {} |
| #endif |
| |
| #ifdef __Fuchsia__ |
| void Runner::Shutdown(fs::FuchsiaVfs::ShutdownCallback cb) { |
| TRACE_DURATION("minfs", "Runner::Shutdown"); |
| FX_LOGS(INFO) << "Shutting down"; |
| ManagedVfs::Shutdown([this, cb = std::move(cb)](zx_status_t status) mutable { |
| if (status != ZX_OK) { |
| FX_LOGS(ERROR) << "Managed VFS shutdown failed with status: " << zx_status_get_string(status); |
| } |
| minfs_->Sync([this, cb = std::move(cb)](zx_status_t sync_status) mutable { |
| if (sync_status != ZX_OK) { |
| FX_LOGS(ERROR) << "Sync at unmount failed with status: " |
| << zx_status_get_string(sync_status); |
| } |
| async::PostTask(dispatcher(), [this, cb = std::move(cb)]() mutable { |
| std::unique_ptr<Bcache> bc = Minfs::Destroy(std::move(minfs_)); |
| bc.reset(); |
| |
| if (on_unmount_) { |
| on_unmount_(); |
| } |
| |
| // Tell the unmounting channel that we've completed teardown. This *must* be the last thing |
| // we do because after this, the caller can assume that it's safe to destroy the runner. |
| cb(ZX_OK); |
| }); |
| }); |
| }); |
| } |
| |
| zx::result<fs::FilesystemInfo> Runner::GetFilesystemInfo() { return minfs_->GetFilesystemInfo(); } |
| |
| zx::result<> Runner::ServeRoot(fidl::ServerEnd<fuchsia_io::Directory> root) { |
| auto vn = minfs_->VnodeGet(kMinfsRootIno); |
| if (vn.is_error()) { |
| FX_LOGS(ERROR) << "cannot find root inode: " << vn.is_error(); |
| return vn.take_error(); |
| } |
| |
| auto outgoing = fbl::MakeRefCounted<fs::PseudoDir>(); |
| outgoing->AddEntry("root", *std::move(vn)); |
| |
| outgoing->AddEntry( |
| fidl::DiscoverableProtocolName<fuchsia_fs::Admin>, |
| fbl::MakeRefCounted<AdminService>(dispatcher_, [this](fs::FuchsiaVfs::ShutdownCallback cb) { |
| this->Shutdown(std::move(cb)); |
| })); |
| |
| zx_status_t status = ServeDirectory(std::move(outgoing), std::move(root)); |
| if (status != ZX_OK) { |
| return zx::error(status); |
| } |
| |
| return zx::ok(); |
| } |
| |
| void Runner::OnNoConnections() { |
| if (IsTerminating()) { |
| return; |
| } |
| Shutdown([](zx_status_t status) mutable { |
| ZX_ASSERT_MSG(status == ZX_OK, "Filesystem shutdown failed on OnNoConnections(): %s", |
| zx_status_get_string(status)); |
| }); |
| } |
| #endif // __Fuchsia__ |
| |
| bool Runner::IsReadonly() const { |
| std::lock_guard lock(vfs_lock_); |
| return ReadonlyLocked(); |
| } |
| |
| } // namespace minfs |