blob: 928fc14cc71376268e47ef62219c39d3c7c35668 [file] [log] [blame]
// Copyright 2019 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.
#ifndef SRC_STORAGE_FSHOST_DELAYED_OUTDIR_H_
#define SRC_STORAGE_FSHOST_DELAYED_OUTDIR_H_
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fit/bridge.h>
#include <lib/fit/result.h>
#include <lib/fit/single_threaded_executor.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/channel.h>
#include <zircon/status.h>
#include <zircon/types.h>
#include <fs/managed_vfs.h>
#include <fs/pseudo_dir.h>
#include <fs/remote_dir.h>
#include <fs/vfs.h>
#include <fs/vfs_types.h>
namespace devmgr {
// TODO(fxbug.dev/39588): This class is used to create a new RemoteDir that doesn't
// respond to any messages until `.Start()` is called. This is important for
// signaling to devcoordinator and component manager when they can start
// accessing data from pkgfs. This solution is fairly hacky, and will hopefully
// not be very long lived. Ideally the filesystems will properly pipeline
// requests, wherein each filesystem would not respond to requests until it was
// initialized.
class DelayedOutdir {
public:
DelayedOutdir()
: outgoing_dir_delayed_loop_(new async::Loop(&kAsyncLoopConfigNoAttachToCurrentThread)),
delayed_vfs_(fs::ManagedVfs(outgoing_dir_delayed_loop_->dispatcher())),
started_(false) {}
~DelayedOutdir() {
if (started_) {
// If we've been started, we need to shutdown the VFS before destroying
// it, otherwise the VFS might panic.
fit::bridge<zx_status_t> bridge;
delayed_vfs_.Shutdown(bridge.completer.bind());
auto promise_shutdown = bridge.consumer.promise_or(::fit::error());
fit::result<zx_status_t, void> result = fit::run_single_threaded(std::move(promise_shutdown));
if (!result.is_ok()) {
FX_LOGS(ERROR) << "error running fit executor to shutdown delayed outdir vfs";
} else if (result.value() != ZX_OK) {
FX_LOGS(ERROR) << "error shutting down delayed outdir vfs: "
<< zx_status_get_string(result.value());
}
}
}
fbl::RefPtr<fs::RemoteDir> Initialize(
fidl::ClientEnd<::llcpp::fuchsia::io::Directory> filesystems_client) {
auto delayed_dir = fbl::MakeRefCounted<fs::PseudoDir>();
delayed_dir->AddEntry("fs", fbl::MakeRefCounted<fs::RemoteDir>(std::move(filesystems_client)));
// Add the delayed vfs to the main one under /delayed
auto delayed = fidl::CreateEndpoints<::llcpp::fuchsia::io::Directory>();
if (!delayed.is_ok()) {
FX_LOGS(ERROR) << "delayed outdir failed to create channel";
return fbl::RefPtr<fs::RemoteDir>();
}
delayed_vfs_.ServeDirectory(delayed_dir, std::move(delayed->server));
return fbl::MakeRefCounted<fs::RemoteDir>(std::move(delayed->client));
}
void Start() {
outgoing_dir_delayed_loop_->StartThread("delayed_outgoing_dir");
started_ = true;
}
private:
std::unique_ptr<async::Loop> outgoing_dir_delayed_loop_;
fs::ManagedVfs delayed_vfs_;
bool started_;
};
} // namespace devmgr
#endif // SRC_STORAGE_FSHOST_DELAYED_OUTDIR_H_