blob: 77ae5b2fc918ea551cdce8ce11e54d7fc855ca0e [file] [log] [blame]
// 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