mirror of
https://github.com/RGBCube/serenity
synced 2025-05-19 16:55:07 +00:00

The idea is to enable mounting FileSystem objects across multiple mounts in contrast to what happened until now - each mount has its own unique FileSystem object being attached to it. Considering a situation of mounting a block device at 2 different mount points at in system, there were a couple of critical flaws due to how the previous "design" worked: 1. BlockBasedFileSystem(s) that pointed to the same actual device had a separate DiskCache object being attached to them. Because both instances were not synchronized by any means, corruption of the filesystem is most likely achieveable by a simple cache flush of either of the instances. 2. For superblock-oriented filesystems (such as the ext2 filesystem), lack of synchronization between both instances can lead to severe corruption in the superblock, which could render the entire filesystem unusable. 3. Flags of a specific filesystem implementation (for example, with xfs on Linux, one can instruct to mount it with the discard option) must be honored across multiple mounts, to ensure expected behavior against a particular filesystem. This patch put the foundations to start fix the issues mentioned above. However, there are still major issues to solve, so this is only a start.
111 lines
5.1 KiB
C++
111 lines
5.1 KiB
C++
/*
|
|
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/Badge.h>
|
|
#include <AK/Error.h>
|
|
#include <AK/Function.h>
|
|
#include <AK/HashMap.h>
|
|
#include <AK/NonnullOwnPtrVector.h>
|
|
#include <AK/OwnPtr.h>
|
|
#include <AK/RefPtr.h>
|
|
#include <Kernel/FileSystem/FileBackedFileSystem.h>
|
|
#include <Kernel/FileSystem/FileSystem.h>
|
|
#include <Kernel/FileSystem/InodeIdentifier.h>
|
|
#include <Kernel/FileSystem/InodeMetadata.h>
|
|
#include <Kernel/FileSystem/Mount.h>
|
|
#include <Kernel/FileSystem/UnveilNode.h>
|
|
#include <Kernel/Forward.h>
|
|
#include <Kernel/Library/LockRefPtr.h>
|
|
#include <Kernel/Locking/SpinlockProtected.h>
|
|
|
|
namespace Kernel {
|
|
|
|
// Kernel internal options.
|
|
#define O_NOFOLLOW_NOERROR (1 << 29)
|
|
#define O_UNLINK_INTERNAL (1 << 30)
|
|
|
|
struct UidAndGid {
|
|
UserID uid;
|
|
GroupID gid;
|
|
};
|
|
|
|
class VirtualFileSystem {
|
|
public:
|
|
// Required to be at least 8 by POSIX
|
|
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html
|
|
static constexpr int symlink_recursion_limit = 8;
|
|
|
|
static void initialize();
|
|
static VirtualFileSystem& the();
|
|
|
|
VirtualFileSystem();
|
|
~VirtualFileSystem();
|
|
|
|
ErrorOr<void> mount_root(FileSystem&);
|
|
ErrorOr<void> mount(FileSystem&, Custody& mount_point, int flags);
|
|
ErrorOr<void> bind_mount(Custody& source, Custody& mount_point, int flags);
|
|
ErrorOr<void> remount(Custody& mount_point, int new_flags);
|
|
ErrorOr<void> unmount(Custody& mount_point);
|
|
|
|
ErrorOr<NonnullLockRefPtr<OpenFileDescription>> open(Credentials const&, StringView path, int options, mode_t mode, Custody& base, Optional<UidAndGid> = {});
|
|
ErrorOr<NonnullLockRefPtr<OpenFileDescription>> create(Credentials const&, StringView path, int options, mode_t mode, Custody& parent_custody, Optional<UidAndGid> = {});
|
|
ErrorOr<void> mkdir(Credentials const&, StringView path, mode_t mode, Custody& base);
|
|
ErrorOr<void> link(Credentials const&, StringView old_path, StringView new_path, Custody& base);
|
|
ErrorOr<void> unlink(Credentials const&, StringView path, Custody& base);
|
|
ErrorOr<void> symlink(Credentials const&, StringView target, StringView linkpath, Custody& base);
|
|
ErrorOr<void> rmdir(Credentials const&, StringView path, Custody& base);
|
|
ErrorOr<void> chmod(Credentials const&, StringView path, mode_t, Custody& base, int options = 0);
|
|
ErrorOr<void> chmod(Credentials const&, Custody&, mode_t);
|
|
ErrorOr<void> chown(Credentials const&, StringView path, UserID, GroupID, Custody& base, int options);
|
|
ErrorOr<void> chown(Credentials const&, Custody&, UserID, GroupID);
|
|
ErrorOr<void> access(Credentials const&, StringView path, int mode, Custody& base);
|
|
ErrorOr<InodeMetadata> lookup_metadata(Credentials const&, StringView path, Custody& base, int options = 0);
|
|
ErrorOr<void> utime(Credentials const&, StringView path, Custody& base, time_t atime, time_t mtime);
|
|
ErrorOr<void> utimensat(Credentials const&, StringView path, Custody& base, timespec const& atime, timespec const& mtime, int options = 0);
|
|
ErrorOr<void> rename(Credentials const&, StringView oldpath, StringView newpath, Custody& base);
|
|
ErrorOr<void> mknod(Credentials const&, StringView path, mode_t, dev_t, Custody& base);
|
|
ErrorOr<NonnullRefPtr<Custody>> open_directory(Credentials const&, StringView path, Custody& base);
|
|
|
|
ErrorOr<void> for_each_mount(Function<ErrorOr<void>(Mount const&)>) const;
|
|
|
|
ErrorOr<NonnullLockRefPtr<FileBackedFileSystem>> find_already_existing_or_create_file_backed_file_system(OpenFileDescription& description, Function<ErrorOr<NonnullLockRefPtr<FileSystem>>(OpenFileDescription&)> callback);
|
|
|
|
InodeIdentifier root_inode_id() const;
|
|
|
|
static void sync();
|
|
|
|
NonnullRefPtr<Custody> root_custody();
|
|
ErrorOr<NonnullRefPtr<Custody>> resolve_path(Credentials const&, StringView path, NonnullRefPtr<Custody> base, RefPtr<Custody>* out_parent = nullptr, int options = 0, int symlink_recursion_level = 0);
|
|
ErrorOr<NonnullRefPtr<Custody>> resolve_path_without_veil(Credentials const&, StringView path, NonnullRefPtr<Custody> base, RefPtr<Custody>* out_parent = nullptr, int options = 0, int symlink_recursion_level = 0);
|
|
|
|
private:
|
|
friend class OpenFileDescription;
|
|
|
|
UnveilNode const& find_matching_unveiled_path(StringView path);
|
|
ErrorOr<void> validate_path_against_process_veil(Custody const& path, int options);
|
|
ErrorOr<void> validate_path_against_process_veil(StringView path, int options);
|
|
|
|
bool is_vfs_root(InodeIdentifier) const;
|
|
|
|
ErrorOr<void> traverse_directory_inode(Inode&, Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)>);
|
|
|
|
bool mount_point_exists_at_inode(InodeIdentifier inode);
|
|
|
|
// FIXME: These functions are totally unsafe as someone could unmount the returned Mount underneath us.
|
|
Mount* find_mount_for_host(InodeIdentifier);
|
|
Mount* find_mount_for_guest(InodeIdentifier);
|
|
|
|
LockRefPtr<Inode> m_root_inode;
|
|
|
|
SpinlockProtected<RefPtr<Custody>> m_root_custody;
|
|
|
|
SpinlockProtected<Vector<NonnullOwnPtr<Mount>, 16>> m_mounts { LockRank::None };
|
|
SpinlockProtected<IntrusiveList<&FileBackedFileSystem::m_file_backed_file_system_node>> m_file_backed_file_systems_list { LockRank::None };
|
|
};
|
|
|
|
}
|