blob: 525d7daa17150e917edc472cf312058387b846cc [file] [log] [blame]
// 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 "filesystem-mounter.h"
#include <lib/zx/process.h>
#include <zircon/status.h>
#include <fs-management/mount.h>
#include <minfs/minfs.h>
#include "../shared/fdio.h"
#include "fshost-fs-provider.h"
#include "pkgfs-launcher.h"
namespace devmgr {
zx_status_t FilesystemMounter::LaunchFs(int argc, const char** argv, zx_handle_t* hnd,
uint32_t* ids, size_t len) {
FshostFsProvider fs_provider;
DevmgrLauncher launcher(&fs_provider);
return launcher.Launch(*zx::job::default_job(), argv[0], argv, nullptr, -1,
/* TODO(fxb/32044) */ zx::resource(), hnd, ids, len, nullptr,
FS_FOR_FSPROC);
}
zx_status_t FilesystemMounter::MountFilesystem(const char* mount_path, const char* binary,
const mount_options_t& options,
zx::channel block_device_client) {
zx::channel client, server;
zx_status_t status = zx::channel::create(0, &client, &server);
if (status != ZX_OK) {
return status;
}
constexpr size_t kNumHandles = 2;
zx_handle_t handles[kNumHandles] = {
server.release(),
block_device_client.release(),
};
uint32_t ids[kNumHandles] = {
FS_HANDLE_ROOT_ID,
FS_HANDLE_BLOCK_DEVICE_ID,
};
fbl::Vector<const char*> argv;
argv.push_back(binary);
if (options.readonly) {
argv.push_back("--readonly");
}
if (options.verbose_mount) {
argv.push_back("--verbose");
}
if (options.collect_metrics) {
argv.push_back("--metrics");
}
if (options.enable_journal) {
argv.push_back("--journal");
}
if (options.enable_pager) {
argv.push_back("--pager");
}
argv.push_back("mount");
argv.push_back(nullptr);
status = LaunchFs(static_cast<int>(argv.size() - 1), argv.data(), handles, ids, kNumHandles);
if (status != ZX_OK) {
return status;
}
zx_signals_t observed = 0;
status =
client.wait_one(ZX_USER_SIGNAL_0 | ZX_CHANNEL_PEER_CLOSED, zx::time::infinite(), &observed);
if ((status != ZX_OK) || (observed & ZX_CHANNEL_PEER_CLOSED)) {
status = (status != ZX_OK) ? status : ZX_ERR_BAD_STATE;
return status;
}
return InstallFs(mount_path, std::move(client));
}
zx_status_t FilesystemMounter::MountData(zx::channel block_device, const mount_options_t& options) {
if (data_mounted_) {
return ZX_ERR_ALREADY_BOUND;
}
zx_status_t status =
MountFilesystem(PATH_DATA, "/boot/bin/minfs", options, std::move(block_device));
if (status != ZX_OK) {
return status;
}
data_mounted_ = true;
return ZX_OK;
}
zx_status_t FilesystemMounter::MountInstall(zx::channel block_device,
const mount_options_t& options) {
if (install_mounted_) {
return ZX_ERR_ALREADY_BOUND;
}
zx_status_t status =
MountFilesystem(PATH_INSTALL, "/boot/bin/minfs", options, std::move(block_device));
if (status != ZX_OK) {
return status;
}
install_mounted_ = true;
return ZX_OK;
}
zx_status_t FilesystemMounter::MountBlob(zx::channel block_device, const mount_options_t& options) {
if (blob_mounted_) {
return ZX_ERR_ALREADY_BOUND;
}
zx_status_t status =
MountFilesystem(PATH_BLOB, "/boot/bin/blobfs", options, std::move(block_device));
if (status != ZX_OK) {
return status;
}
blob_mounted_ = true;
return ZX_OK;
}
void FilesystemMounter::TryMountPkgfs() {
// Pkgfs waits for the following to mount before initializing:
// - Blobfs. Pkgfs is launched from blobfs, so this is a hard requirement.
// - Minfs. Pkgfs and other components want minfs to exist, so although they
// could launch and query for it later, this synchronization point means that
// subsequent clients will no longer need to query.
//
// TODO(fxb/38621): In the future, this mechanism may be replaced with a feed-forward
// design to the mounted filesystems.
if (!pkgfs_mounted_ && blob_mounted_ && (data_mounted_ || !WaitForData())) {
LaunchPkgfs(this);
pkgfs_mounted_ = true;
}
}
} // namespace devmgr