blob: 41777fe0bcda9ea8850521e55ca71ecb752e9947 [file] [log] [blame]
// Copyright 2021 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_LIB_VFS_CPP_FUCHSIA_VFS_H_
#define SRC_STORAGE_LIB_VFS_CPP_FUCHSIA_VFS_H_
#include <fidl/fuchsia.fs/cpp/wire.h>
#include <fidl/fuchsia.io/cpp/wire.h>
#include <lib/async/dispatcher.h>
#include <lib/fit/function.h>
#include <lib/zx/channel.h>
#include <lib/zx/event.h>
#include <lib/zx/result.h>
#include <lib/zx/vmo.h>
#include <zircon/types.h>
#include <cstdint>
#include <string>
#include <fbl/intrusive_double_list.h>
#include <fbl/intrusive_hash_table.h>
#include <fbl/macros.h>
#include <fbl/ref_counted.h>
#include <fbl/ref_ptr.h>
#include "src/storage/lib/vfs/cpp/vfs.h"
namespace fs {
namespace internal {
class Connection;
} // namespace internal
// An internal version of fuchsia_io::wire::FilesystemInfo with a simpler API and default
// initializers. See that FIDL struct for documentation.
struct FilesystemInfo {
uint64_t total_bytes = 0;
uint64_t used_bytes = 0;
uint64_t total_nodes = 0;
uint64_t used_nodes = 0;
uint64_t free_shared_pool_bytes = 0;
uint64_t fs_id = 0;
uint32_t block_size = 0;
uint32_t max_filename_size = 0;
fuchsia_fs::VfsType fs_type = fuchsia_fs::VfsType::Unknown();
std::string name; // Length must be less than MAX_FS_NAME_BUFFER.
// To ensure global uniqueness, filesystems should create and maintain an event object. The koid
// of this object is guaranteed unique in the system and is used for the filesystem ID. This
// function extracts the koid of the given event object and sets it as the filesystem ID.
void SetFsId(const zx::event& event);
// Writes this object's values to the given FIDL object.
fuchsia_io::wire::FilesystemInfo ToFidl() const;
};
// Vfs specialization that adds Fuchsia-specific
class FuchsiaVfs : public Vfs {
public:
explicit FuchsiaVfs(async_dispatcher_t* dispatcher = nullptr);
~FuchsiaVfs() override;
using ShutdownCallback = fit::callback<void(zx_status_t status)>;
using CloseAllConnectionsForVnodeCallback = fit::callback<void()>;
// Unmounts the underlying filesystem. The result of shutdown is delivered via calling |closure|.
//
// |Shutdown| may be synchronous or asynchronous. The closure may be invoked before or after
// |Shutdown| returns.
virtual void Shutdown(ShutdownCallback closure) = 0;
// Identifies if the filesystem is in the process of terminating. May be checked by active
// connections, which, upon reading new port packets, should ignore them and close immediately.
virtual bool IsTerminating() const = 0;
// Vfs overrides.
zx_status_t Unlink(fbl::RefPtr<Vnode> vn, std::string_view name, bool must_be_dir) override
__TA_EXCLUDES(vfs_lock_);
void TokenDiscard(zx::event ios_token) __TA_EXCLUDES(vfs_lock_);
zx_status_t VnodeToToken(fbl::RefPtr<Vnode> vn, zx::event* ios_token, zx::event* out)
__TA_EXCLUDES(vfs_lock_);
zx_status_t Link(zx::event token, fbl::RefPtr<Vnode> oldparent, std::string_view oldStr,
std::string_view newStr) __TA_EXCLUDES(vfs_lock_);
zx_status_t Rename(zx::event token, fbl::RefPtr<Vnode> oldparent, std::string_view oldStr,
std::string_view newStr) __TA_EXCLUDES(vfs_lock_);
// Provides the implementation for fuchsia.io.Directory.QueryFilesystem().
// This default implementation returns ZX_ERR_NOT_SUPPORTED.
virtual zx::result<FilesystemInfo> GetFilesystemInfo() __TA_EXCLUDES(vfs_lock_);
async_dispatcher_t* dispatcher() const { return dispatcher_; }
void SetDispatcher(async_dispatcher_t* dispatcher);
// Begins serving VFS messages over the specified channel. The protocol to use will be determined
// by the intersection of the protocols requested in |options| and those supported by |vnode|.
// |server_end| usually speaks a protocol that composes |fuchsia.io/Node|, but may speak an
// arbitrary arbitrary protocol for service connections.
//
// *NOTE*: |vnode| must be opened before calling this function, and will be automatically closed
// on failure. This does not apply to node reference connections, which should not open |vnode|.
zx_status_t Serve(const fbl::RefPtr<Vnode>& vnode, zx::channel server_end,
VnodeConnectionOptions options) __TA_EXCLUDES(vfs_lock_);
// Serves a Vnode over the specified channel (used for creating new filesystems); the Vnode must
// be a directory.
zx_status_t ServeDirectory(fbl::RefPtr<Vnode> vn,
fidl::ServerEnd<fuchsia_io::Directory> server_end,
fuchsia_io::Rights rights);
// Convenience wrapper over |ServeDirectory| with maximum rights.
zx_status_t ServeDirectory(fbl::RefPtr<Vnode> vn,
fidl::ServerEnd<fuchsia_io::Directory> server_end) {
return ServeDirectory(std::move(vn), std::move(server_end), fuchsia_io::Rights::kMask);
}
// Closes all connections to a Vnode and calls |callback| after all connections are closed. The
// caller must ensure that no new connections or transactions are created during this point.
virtual void CloseAllConnectionsForVnode(const Vnode& node,
CloseAllConnectionsForVnodeCallback callback) = 0;
bool IsTokenAssociatedWithVnode(zx::event token) __TA_EXCLUDES(vfs_lock_);
protected:
// On success, |vnode| will automatically be closed when fuchsia.io/Node.Close is called, or
// |server_end| is closed. On failure, callers must close |vnode| if it was opened.
zx_status_t ServeImpl(const fbl::RefPtr<Vnode>& vnode, zx::channel server_end,
VnodeConnectionOptions options) __TA_EXCLUDES(vfs_lock_);
// Starts FIDL message dispatching on |channel|, at the same time starts to manage the lifetime of
// |connection|. On error registering a connection, callers must close the associated vnode.
virtual zx_status_t RegisterConnection(std::unique_ptr<internal::Connection> connection,
zx::channel channel) = 0;
private:
zx_status_t TokenToVnode(zx::event token, fbl::RefPtr<Vnode>* out) __TA_REQUIRES(vfs_lock_);
fbl::HashTable<zx_koid_t, std::unique_ptr<VnodeToken>> vnode_tokens_;
async_dispatcher_t* dispatcher_ = nullptr;
};
} // namespace fs
#endif // SRC_STORAGE_LIB_VFS_CPP_FUCHSIA_VFS_H_