From a7484bf9c18c02a560df57215e7af3215dce2e6e Mon Sep 17 00:00:00 2001 From: Lucjan Bryndza Date: Tue, 22 Dec 2020 13:32:33 +0100 Subject: [PATCH] [EGD-4754] Add automount default filesystems Default automount and parse partitions according to their configurations using new vfs core. Currently old (without lfs) and new (with lfs) part schemes are supported --- .../linux/purefs/src/blkdev/disk_image.cpp | 16 +- .../linux/purefs/src/fs/thread_local_cwd.cpp | 10 +- .../rt1051/purefs/src/fs/thread_local_cwd.cpp | 7 +- .../internal/purefs/blkdev/disk_handle.hpp | 2 +- .../internal/purefs/fs/mount_point.hpp | 3 +- .../internal/purefs/fs/thread_local_cwd.hpp | 1 + .../include/user/purefs/vfs_subsystem.hpp | 1 + module-vfs/src/purefs/vfs_subsystem.cpp | 139 +++++++++++++++++- module-vfs/tests/unittest_filesystem_core.cpp | 12 ++ 9 files changed, 176 insertions(+), 15 deletions(-) diff --git a/module-vfs/board/linux/purefs/src/blkdev/disk_image.cpp b/module-vfs/board/linux/purefs/src/blkdev/disk_image.cpp index 5c60be6b29513909830334a226abe4965a350764..dad9705040eb24eb5d2c64fc2d1b05d01fec0629 100644 --- a/module-vfs/board/linux/purefs/src/blkdev/disk_image.cpp +++ b/module-vfs/board/linux/purefs/src/blkdev/disk_image.cpp @@ -39,14 +39,14 @@ namespace purefs::blkdev } auto disk_image::write(const void *buf, sector_t lba, std::size_t count) -> int { - int ret = ::lseek(m_filedes, lba * sector_size, SEEK_SET); - if (ret < 0) { - return ret; + auto offs = ::lseek(m_filedes, off_t(lba) * sector_size, SEEK_SET); + if (offs < 0) { + return offs; } auto to_write = count * sector_size; auto buf_b = reinterpret_cast(buf); do { - ret = ::write(m_filedes, buf_b, to_write); + auto ret = ::write(m_filedes, buf_b, to_write); if (ret < 0) { return -errno; } @@ -57,14 +57,14 @@ namespace purefs::blkdev } auto disk_image::read(void *buf, sector_t lba, std::size_t count) -> int { - int ret = ::lseek(m_filedes, lba * sector_size, SEEK_SET); - if (ret < 0) { - return ret; + auto offs = ::lseek(m_filedes, off_t(lba) * sector_size, SEEK_SET); + if (offs < 0) { + return offs; } auto to_read = count * sector_size; auto buf_b = reinterpret_cast(buf); do { - ret = ::read(m_filedes, buf_b, to_read); + auto ret = ::read(m_filedes, buf_b, to_read); if (ret < 0) { return -errno; } diff --git a/module-vfs/board/linux/purefs/src/fs/thread_local_cwd.cpp b/module-vfs/board/linux/purefs/src/fs/thread_local_cwd.cpp index 77750d2cb8d6e5052d060e9e4ed9393df73864f8..99d399f3e2506d1469dc3201b20637a54f8f480e 100644 --- a/module-vfs/board/linux/purefs/src/fs/thread_local_cwd.cpp +++ b/module-vfs/board/linux/purefs/src/fs/thread_local_cwd.cpp @@ -9,10 +9,14 @@ namespace purefs::fs::internal namespace { - thread_local std::string cwd_per_thread{"/"}; + thread_local std::string cwd_per_thread; + std::string default_cwd{"/"}; } auto get_thread_local_cwd_path() noexcept -> std::string_view { + if (cwd_per_thread.empty()) { + cwd_per_thread = default_cwd; + } return cwd_per_thread; } auto set_thread_cwd_path(std::string_view path) noexcept -> int @@ -24,4 +28,8 @@ namespace purefs::fs::internal { cwd_per_thread.erase(); } + auto set_default_thread_cwd(std::string_view str) noexcept -> void + { + default_cwd = str; + } } // namespace purefs::fs::internal diff --git a/module-vfs/board/rt1051/purefs/src/fs/thread_local_cwd.cpp b/module-vfs/board/rt1051/purefs/src/fs/thread_local_cwd.cpp index 48eb12ccc2d67335497274836146c90a521182a4..86581313f59175058a613f5846eb50282b51dd83 100644 --- a/module-vfs/board/rt1051/purefs/src/fs/thread_local_cwd.cpp +++ b/module-vfs/board/rt1051/purefs/src/fs/thread_local_cwd.cpp @@ -14,13 +14,14 @@ namespace purefs::fs::internal namespace { constexpr auto CWD_THREAD_LOCAL_INDEX = 3; + std::string g_default_cwd{"/"}; auto get_tls() noexcept -> char * { auto pcwd = reinterpret_cast(pvTaskGetThreadLocalStoragePointer(nullptr, CWD_THREAD_LOCAL_INDEX)); if (pcwd == nullptr) { pcwd = new (std::nothrow) char[PATH_MAX + 1]; if (pcwd) { - std::strncpy(pcwd, "/", PATH_MAX); + std::strncpy(pcwd, g_default_cwd.c_str(), PATH_MAX); vTaskSetThreadLocalStoragePointer(nullptr, CWD_THREAD_LOCAL_INDEX, pcwd); } } @@ -54,4 +55,8 @@ namespace purefs::fs::internal vTaskSetThreadLocalStoragePointer(nullptr, CWD_THREAD_LOCAL_INDEX, nullptr); } } + auto set_default_thread_cwd(std::string_view str) noexcept -> void + { + g_default_cwd = str; + } } // namespace purefs::fs::internal diff --git a/module-vfs/include/internal/purefs/blkdev/disk_handle.hpp b/module-vfs/include/internal/purefs/blkdev/disk_handle.hpp index 3ae478866d8ef3a1bcec1b24ab16bf98d821a51b..b246c3f60ec7d079d65756055351e6a919b30762 100644 --- a/module-vfs/include/internal/purefs/blkdev/disk_handle.hpp +++ b/module-vfs/include/internal/purefs/blkdev/disk_handle.hpp @@ -44,6 +44,6 @@ namespace purefs::blkdev::internal const std::weak_ptr m_disk; const short m_partition{-1}; mutable sector_t m_sectors{0}; - const std::string_view m_name; + const std::string m_name; }; } // namespace purefs::blkdev::internal diff --git a/module-vfs/include/internal/purefs/fs/mount_point.hpp b/module-vfs/include/internal/purefs/fs/mount_point.hpp index 0e85493190e43b0e507f390b1715d5c4a0140d3c..e7028957f5d65dd99cc99dd280549026e565d5d9 100644 --- a/module-vfs/include/internal/purefs/fs/mount_point.hpp +++ b/module-vfs/include/internal/purefs/fs/mount_point.hpp @@ -4,6 +4,7 @@ #pragma once #include #include +#include namespace purefs::blkdev::internal { @@ -63,7 +64,7 @@ namespace purefs::fs::internal private: const std::weak_ptr m_diskh; - const std::string_view m_path; //! Mounted path + const std::string m_path; //! Mounted path const std::weak_ptr m_fs; //! Filesystem operation const unsigned m_flags; }; diff --git a/module-vfs/include/internal/purefs/fs/thread_local_cwd.hpp b/module-vfs/include/internal/purefs/fs/thread_local_cwd.hpp index fde437601e400024090314db77a0da559426abb8..4c631e172c5898f08d05c3aebb1ca54990595050 100644 --- a/module-vfs/include/internal/purefs/fs/thread_local_cwd.hpp +++ b/module-vfs/include/internal/purefs/fs/thread_local_cwd.hpp @@ -9,4 +9,5 @@ namespace purefs::fs::internal auto get_thread_local_cwd_path() noexcept -> std::string_view; auto set_thread_cwd_path(std::string_view path) noexcept -> int; auto cleanup_thread_local_cwd_mem() -> void; + auto set_default_thread_cwd(std::string_view str) noexcept -> void; } // namespace purefs::fs::internal diff --git a/module-vfs/include/user/purefs/vfs_subsystem.hpp b/module-vfs/include/user/purefs/vfs_subsystem.hpp index 190992b724701a14421d549dd9d8307919d4c422..0d7c2293361d0ce7a7c622798439b93f66f9d2a3 100644 --- a/module-vfs/include/user/purefs/vfs_subsystem.hpp +++ b/module-vfs/include/user/purefs/vfs_subsystem.hpp @@ -11,4 +11,5 @@ namespace purefs::subsystem auto initialize() -> std::tuple, std::shared_ptr>; auto disk_mgr() -> std::shared_ptr; auto vfs_core() -> std::shared_ptr; + auto mount_defaults() -> int; } // namespace purefs::subsystem diff --git a/module-vfs/src/purefs/vfs_subsystem.cpp b/module-vfs/src/purefs/vfs_subsystem.cpp index 2e5fa9a090f529189f8752a1779e7f2f6fe3e1c0..37721a0064e3b99f109c14b770be811d4c972694 100644 --- a/module-vfs/src/purefs/vfs_subsystem.cpp +++ b/module-vfs/src/purefs/vfs_subsystem.cpp @@ -2,21 +2,95 @@ // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include +#include +#include #include #include #include +#include #include +#include +#include +#include +#include namespace purefs::subsystem { namespace { constexpr auto default_blkdev_name = "emmc0"; - + constexpr auto fat_part_code = 0x0b; + constexpr auto lfs_part_code = 0x9e; + constexpr auto old_layout_part_count = 2; + constexpr auto new_layout_part_count = 3; + constexpr auto boot_size_limit = 16384L; + namespace json + { + constexpr auto os_type = "ostype"; + constexpr auto main = "main"; + } // namespace json std::weak_ptr g_disk_mgr; std::weak_ptr g_fs_core; } // namespace + namespace + { + int read_file_to_cpp_string(std::shared_ptr vfs, std::string_view file, std::string &str) + { + int fd = vfs->open(file, O_RDONLY, 0664); + if (fd < 0) { + return fd; + } + size_t rd_pos = 0; + size_t to_read = str.size(); + do { + int err = vfs->read(fd, &str[rd_pos], to_read); + if (err < 0) { + vfs->close(fd); + return err; + } + else { + to_read -= err; + rd_pos += err; + } + } while (to_read > 0); + return vfs->close(fd); + } + + std::string parse_boot_json_directory(std::string_view file) + { + using namespace std::literals; + auto vfsn = g_fs_core.lock(); + if (!vfsn) { + LOG_ERROR("Unable to lock vfs. Fallback to current dir"); + return "current"s; + } + struct stat stbuf; + int err = vfsn->stat(file, stbuf); + if (err) { + LOG_ERROR("Unable to lock vfs fallback to current dir"); + return "current"s; + } + if (stbuf.st_size > boot_size_limit) { + LOG_ERROR("Boot file to long fallback to current dir"); + return "current"s; + } + std::string json_str(stbuf.st_size, ' '); + std::string error; + err = read_file_to_cpp_string(vfsn, file, json_str); + if (err) { + LOG_ERROR("Unable to read boot file fallback to current dir err %i", err); + return "current"s; + } + auto json = json11::Json::parse(json_str, error); + if (!error.empty()) { + LOG_ERROR("Unable to parse json boot file fallback to current dir error %s", error.c_str()); + return "current"s; + } + return json[json::main][json::os_type].string_value(); + } + } // namespace + auto initialize() -> std::tuple, std::shared_ptr> { auto disk_mgr = std::make_shared(); @@ -24,9 +98,20 @@ namespace purefs::subsystem auto err = disk_mgr->register_device(bdev, default_blkdev_name); if (err) { LOG_FATAL("Unable to register block device with error %i", err); - std::abort(); + return {}; + } + auto fs_core = std::make_shared(disk_mgr); + err = fs_core->register_filesystem("vfat", std::make_shared()); + if (err) { + LOG_FATAL("Unable to register vfat filesystem with error %i", err); + return {}; } - auto fs_core = std::make_shared(g_disk_mgr.lock()); + err = fs_core->register_filesystem("littlefs", std::make_shared()); + if (err) { + LOG_FATAL("Unable to register vfat filesystem with error %i", err); + return {}; + } + g_disk_mgr = disk_mgr; g_fs_core = fs_core; return {disk_mgr, fs_core}; @@ -41,4 +126,52 @@ namespace purefs::subsystem { return g_fs_core.lock(); } + + auto mount_defaults() -> int + { + auto disk = g_disk_mgr.lock(); + if (!disk) { + LOG_FATAL("Unable to lock disk"); + return -EIO; + } + auto parts = disk->partitions(default_blkdev_name); + if (parts.size() != old_layout_part_count && parts.size() != new_layout_part_count) { + LOG_FATAL("Unknown partition layout part size is %u", unsigned(parts.size())); + } + auto boot_it = std::end(parts); + auto lfs_it = std::end(parts); + for (auto it = std::begin(parts); it != std::end(parts); ++it) { + if (it->bootable && boot_it == std::end(parts)) { + boot_it = it; + } + else if (it->type == lfs_part_code && lfs_it == std::end(parts)) { + lfs_it = it; + } + } + if (lfs_it == std::end(parts) && parts.size() == old_layout_part_count) { + LOG_ERROR("!!!! Danger !!!! FAT partiton layout scheme. Data may be currupted when power loss."); + LOG_WARN("Please upgrade to new partition scheme with LITTLEFS partition."); + } + if (boot_it == std::end(parts)) { + LOG_FATAL("Unable to find boot partition"); + return -ENOENT; + } + auto vfs = g_fs_core.lock(); + if (!vfs) { + LOG_FATAL("Unable to lock vfs core"); + return -EIO; + } + auto err = vfs->mount(boot_it->name, purefs::dir::getRootDiskPath().string(), "vfat"); + if (err) { + return err; + } + if (lfs_it != std::end(parts)) { + err = vfs->mount(lfs_it->name, purefs::dir::getUserDiskPath().string(), "littlefs"); + } + const std::string json_file = (dir::getRootDiskPath() / file::boot_json).string(); + const auto boot_dir_name = parse_boot_json_directory(json_file); + const auto user_dir = (dir::getRootDiskPath() / boot_dir_name).string(); + fs::internal::set_default_thread_cwd(user_dir); + return err; + } } // namespace purefs::subsystem diff --git a/module-vfs/tests/unittest_filesystem_core.cpp b/module-vfs/tests/unittest_filesystem_core.cpp index c195cc67f6562efa341d24e0c37ed11afed44ae0..58352797d6b8e28bbc8d8b23c6af4d5da70ad9b9 100644 --- a/module-vfs/tests/unittest_filesystem_core.cpp +++ b/module-vfs/tests/unittest_filesystem_core.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include #include @@ -269,3 +271,13 @@ TEST_CASE("Corefs: Directory operations") REQUIRE(fscore.umount("/sys") == 0); } } + +TEST_CASE("Unititest integrated subsystem") +{ + auto [disk, vfs] = purefs::subsystem::initialize(); + REQUIRE(purefs::subsystem::mount_defaults() == 0); + REQUIRE(purefs::fs::internal::get_thread_local_cwd_path() == "/sys/current"); + const auto err = vfs->umount("/sys/user"); + REQUIRE((err == 0 || err == -2)); + REQUIRE(vfs->umount("/sys") == 0); +}