| // 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 <inttypes.h> |
| #include <fcntl.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| |
| #include <fbl/ref_ptr.h> |
| #include <fbl/unique_ptr.h> |
| #include <lib/fdio/namespace.h> |
| #include <lib/fdio/vfs.h> |
| #include <fs/vfs.h> |
| #include <lib/async/dispatcher.h> |
| #include <lib/memfs/cpp/vnode.h> |
| #include <lib/memfs/memfs.h> |
| #include <lib/sync/completion.h> |
| #include <zircon/device/vfs.h> |
| |
| #include <utility> |
| |
| #include "dnode.h" |
| |
| struct memfs_filesystem { |
| memfs::Vfs vfs; |
| |
| explicit memfs_filesystem(size_t pages_limit): vfs(pages_limit) { } |
| }; |
| |
| zx_status_t memfs_create_filesystem(async_dispatcher_t* dispatcher, |
| memfs_filesystem_t** out_fs, |
| zx_handle_t* out_root) { |
| uint64_t physmem_size = zx_system_get_physmem(); |
| ZX_DEBUG_ASSERT(physmem_size % PAGE_SIZE == 0); |
| size_t page_limit = physmem_size / PAGE_SIZE; |
| |
| return memfs_create_filesystem_with_page_limit(dispatcher, page_limit, out_fs, out_root); |
| } |
| |
| zx_status_t memfs_create_filesystem_with_page_limit(async_dispatcher_t* dispatcher, |
| size_t max_num_pages, |
| memfs_filesystem_t** out_fs, |
| zx_handle_t* out_root) { |
| ZX_DEBUG_ASSERT(dispatcher != nullptr); |
| ZX_DEBUG_ASSERT(out_fs != nullptr); |
| ZX_DEBUG_ASSERT(out_root != nullptr); |
| |
| zx::channel client, server; |
| zx_status_t status = zx::channel::create(0, &client, &server); |
| if (status != ZX_OK) { |
| return status; |
| } |
| |
| fbl::unique_ptr<memfs_filesystem_t> fs = std::make_unique<memfs_filesystem_t>(max_num_pages); |
| fs->vfs.SetDispatcher(dispatcher); |
| |
| fbl::RefPtr<memfs::VnodeDir> root; |
| if ((status = memfs::CreateFilesystem("<tmp>", &fs->vfs, &root)) != ZX_OK) { |
| return status; |
| } |
| if ((status = fs->vfs.ServeDirectory(std::move(root), std::move(server))) != ZX_OK) { |
| return status; |
| } |
| |
| *out_fs = fs.release(); |
| *out_root = client.release(); |
| return ZX_OK; |
| } |
| |
| zx_status_t memfs_install_at(async_dispatcher_t* dispatcher, const char* path) { |
| uint64_t physmem_size = zx_system_get_physmem(); |
| ZX_DEBUG_ASSERT(physmem_size % PAGE_SIZE == 0); |
| size_t page_limit = physmem_size / PAGE_SIZE; |
| |
| return memfs_install_at_with_page_limit(dispatcher, page_limit, path); |
| } |
| |
| zx_status_t memfs_install_at_with_page_limit(async_dispatcher_t* dispatcher, |
| size_t max_num_pages, const char* path) { |
| fdio_ns_t* ns; |
| zx_status_t status = fdio_ns_get_installed(&ns); |
| if (status != ZX_OK) { |
| return status; |
| } |
| |
| memfs_filesystem_t* fs; |
| zx_handle_t root; |
| status = memfs_create_filesystem_with_page_limit(dispatcher, max_num_pages, &fs, &root); |
| if (status != ZX_OK) { |
| return status; |
| } |
| |
| status = fdio_ns_bind(ns, path, root); |
| if (status != ZX_OK) { |
| memfs_free_filesystem(fs, nullptr); |
| return status; |
| } |
| |
| return ZX_OK; |
| } |
| |
| void memfs_free_filesystem(memfs_filesystem_t* fs, sync_completion_t* unmounted) { |
| ZX_DEBUG_ASSERT(fs != nullptr); |
| fs->vfs.Shutdown([fs, unmounted](zx_status_t status) { |
| delete fs; |
| if (unmounted) { |
| sync_completion_signal(unmounted); |
| } |
| }); |
| } |