| // Copyright 2016 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 <fcntl.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <threads.h> |
| |
| #include <fbl/algorithm.h> |
| #include <fbl/alloc_checker.h> |
| #include <fbl/auto_lock.h> |
| #include <fbl/unique_ptr.h> |
| #include <fs/vfs.h> |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/async/cpp/wait.h> |
| #include <lib/fdio/directory.h> |
| #include <lib/zircon-internal/debug.h> |
| #include <lib/fdio/io.h> |
| #include <zircon/device/vfs.h> |
| #include <zircon/processargs.h> |
| #include <zircon/syscalls.h> |
| #include <zircon/thread_annotations.h> |
| |
| #include <utility> |
| |
| #include "fs-manager.h" |
| |
| #define ZXDEBUG 0 |
| |
| namespace devmgr { |
| |
| // Must appear in the devmgr namespace. |
| // Expected dependency of "shared/fdio.h". |
| // |
| // This is currently exposed in a somewhat odd location to also be |
| // visible to unit tests, avoiding linkage errors. |
| zx::channel fs_clone(const char* path) { |
| if (strcmp(path, "svc") == 0) { |
| path = "/svc"; |
| } else if (strcmp(path, "data") == 0) { |
| path = "/fs/data"; |
| } else if (strcmp(path, "blob") == 0) { |
| path = "/fs/blob"; |
| } else { |
| printf("%s: Cannot clone: %s\n", __FUNCTION__, path); |
| return zx::channel(); |
| } |
| |
| zx::channel client, server; |
| zx_status_t status = zx::channel::create(0, &client, &server); |
| if (status != ZX_OK) { |
| return zx::channel(); |
| } |
| status = fdio_service_connect(path, server.release()); |
| if (status != ZX_OK) { |
| printf("%s: Failed to connect to %s: %d\n", __FUNCTION__, path, status); |
| return zx::channel(); |
| } |
| return client; |
| } |
| |
| FsManager::FsManager(zx::event fshost_event) |
| : event_(std::move(fshost_event)), |
| global_loop_(new async::Loop(&kAsyncLoopConfigNoAttachToThread)), |
| registry_(global_loop_.get()) { |
| ZX_ASSERT(global_root_ == nullptr); |
| } |
| |
| // In the event that we haven't been explicitly signalled, tear ourself down. |
| FsManager::~FsManager() { |
| if (global_shutdown_.has_handler()) { |
| event_.signal(0, FSHOST_SIGNAL_EXIT); |
| auto deadline = zx::deadline_after(zx::sec(2)); |
| zx_signals_t pending; |
| event_.wait_one(FSHOST_SIGNAL_EXIT_DONE, deadline, &pending); |
| } |
| } |
| |
| zx_status_t FsManager::Create(zx::event fshost_event, std::unique_ptr<FsManager>* out) { |
| auto fs_manager = std::unique_ptr<FsManager>(new FsManager(std::move(fshost_event))); |
| zx_status_t status = fs_manager->Initialize(); |
| if (status != ZX_OK) { |
| return status; |
| } |
| *out = std::move(fs_manager); |
| return ZX_OK; |
| } |
| |
| zx_status_t FsManager::Initialize() { |
| uint64_t physmem_size = zx_system_get_physmem(); |
| ZX_DEBUG_ASSERT(physmem_size % PAGE_SIZE == 0); |
| size_t page_limit = physmem_size / PAGE_SIZE; |
| |
| zx_status_t status = memfs::Vfs::Create("<root>", page_limit, &root_vfs_, &global_root_); |
| if (status != ZX_OK) { |
| return status; |
| } |
| |
| fbl::RefPtr<fs::Vnode> vn; |
| if ((status = global_root_->Create(&vn, "boot", S_IFDIR)) != ZX_OK) { |
| return status; |
| } |
| if ((status = global_root_->Create(&vn, "tmp", S_IFDIR)) != ZX_OK) { |
| return status; |
| } |
| for (unsigned n = 0; n < fbl::count_of(kMountPoints); n++) { |
| fbl::StringPiece pathout; |
| status = root_vfs_->Open(global_root_, &mount_nodes[n], fbl::StringPiece(kMountPoints[n]), |
| &pathout, |
| ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE | ZX_FS_FLAG_CREATE, |
| S_IFDIR); |
| if (status != ZX_OK) { |
| return status; |
| } |
| } |
| |
| global_loop_->StartThread("root-dispatcher"); |
| root_vfs_->SetDispatcher(global_loop_->dispatcher()); |
| return ZX_OK; |
| } |
| |
| zx_status_t FsManager::InstallFs(const char* path, zx::channel h) { |
| for (unsigned n = 0; n < fbl::count_of(kMountPoints); n++) { |
| if (!strcmp(path, kMountPoints[n])) { |
| return root_vfs_->InstallRemote(mount_nodes[n], fs::MountChannel(std::move(h))); |
| } |
| } |
| return ZX_ERR_NOT_FOUND; |
| } |
| |
| zx_status_t FsManager::ServeRoot(zx::channel server) { |
| return root_vfs_->ServeDirectory(global_root_, std::move(server), ZX_FS_RIGHTS); |
| } |
| |
| void FsManager::WatchExit() { |
| global_shutdown_.set_handler([this](async_dispatcher_t* dispatcher, async::Wait* wait, |
| zx_status_t status, const zx_packet_signal_t* signal) { |
| root_vfs_->UninstallAll(ZX_TIME_INFINITE); |
| event_.signal(0, FSHOST_SIGNAL_EXIT_DONE); |
| }); |
| |
| global_shutdown_.set_object(event_.get()); |
| global_shutdown_.set_trigger(FSHOST_SIGNAL_EXIT); |
| global_shutdown_.Begin(global_loop_->dispatcher()); |
| } |
| |
| } // namespace devmgr |