~aleteoryx/muditaos

a7484bf9c18c02a560df57215e7af3215dce2e6e — Lucjan Bryndza 5 years ago f9b9967
[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
M module-vfs/board/linux/purefs/src/blkdev/disk_image.cpp => module-vfs/board/linux/purefs/src/blkdev/disk_image.cpp +8 -8
@@ 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<const uint8_t *>(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<uint8_t *>(buf);
        do {
            ret = ::read(m_filedes, buf_b, to_read);
            auto ret = ::read(m_filedes, buf_b, to_read);
            if (ret < 0) {
                return -errno;
            }

M module-vfs/board/linux/purefs/src/fs/thread_local_cwd.cpp => module-vfs/board/linux/purefs/src/fs/thread_local_cwd.cpp +9 -1
@@ 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

M module-vfs/board/rt1051/purefs/src/fs/thread_local_cwd.cpp => module-vfs/board/rt1051/purefs/src/fs/thread_local_cwd.cpp +6 -1
@@ 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<char *>(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

M module-vfs/include/internal/purefs/blkdev/disk_handle.hpp => module-vfs/include/internal/purefs/blkdev/disk_handle.hpp +1 -1
@@ 44,6 44,6 @@ namespace purefs::blkdev::internal
        const std::weak_ptr<blkdev::disk> 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

M module-vfs/include/internal/purefs/fs/mount_point.hpp => module-vfs/include/internal/purefs/fs/mount_point.hpp +2 -1
@@ 4,6 4,7 @@
#pragma once
#include <memory>
#include <string>
#include <iostream>

namespace purefs::blkdev::internal
{


@@ 63,7 64,7 @@ namespace purefs::fs::internal

      private:
        const std::weak_ptr<blkdev::internal::disk_handle> m_diskh;
        const std::string_view m_path;                   //! Mounted path
        const std::string m_path;                        //! Mounted path
        const std::weak_ptr<filesystem_operations> m_fs; //! Filesystem operation
        const unsigned m_flags;
    };

M module-vfs/include/internal/purefs/fs/thread_local_cwd.hpp => module-vfs/include/internal/purefs/fs/thread_local_cwd.hpp +1 -0
@@ 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

M module-vfs/include/user/purefs/vfs_subsystem.hpp => module-vfs/include/user/purefs/vfs_subsystem.hpp +1 -0
@@ 11,4 11,5 @@ namespace purefs::subsystem
    auto initialize() -> std::tuple<std::shared_ptr<blkdev::disk_manager>, std::shared_ptr<fs::filesystem>>;
    auto disk_mgr() -> std::shared_ptr<blkdev::disk_manager>;
    auto vfs_core() -> std::shared_ptr<fs::filesystem>;
    auto mount_defaults() -> int;
} // namespace purefs::subsystem

M module-vfs/src/purefs/vfs_subsystem.cpp => module-vfs/src/purefs/vfs_subsystem.cpp +136 -3
@@ 2,21 2,95 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <purefs/fs/filesystem.hpp>
#include <purefs/fs/drivers/filesystem_vfat.hpp>
#include <purefs/fs/drivers/filesystem_littlefs.hpp>
#include <purefs/blkdev/disk_manager.hpp>
#include <purefs/vfs_subsystem.hpp>
#include <purefs/vfs_subsystem_internal.hpp>
#include <purefs/fs/thread_local_cwd.hpp>
#include <log/log.hpp>
#include <purefs/filesystem_paths.hpp>
#include <module-utils/json/json11.hpp>
#include <sys/stat.h>
#include <fcntl.h>

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<blkdev::disk_manager> g_disk_mgr;
        std::weak_ptr<fs::filesystem> g_fs_core;
    } // namespace

    namespace
    {
        int read_file_to_cpp_string(std::shared_ptr<fs::filesystem> 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<blkdev::disk_manager>, std::shared_ptr<fs::filesystem>>
    {
        auto disk_mgr   = std::make_shared<blkdev::disk_manager>();


@@ 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<fs::filesystem>(disk_mgr);
        err          = fs_core->register_filesystem("vfat", std::make_shared<fs::drivers::filesystem_vfat>());
        if (err) {
            LOG_FATAL("Unable to register vfat filesystem with error %i", err);
            return {};
        }
        auto fs_core = std::make_shared<fs::filesystem>(g_disk_mgr.lock());
        err = fs_core->register_filesystem("littlefs", std::make_shared<fs::drivers::filesystem_littlefs>());
        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

M module-vfs/tests/unittest_filesystem_core.cpp => module-vfs/tests/unittest_filesystem_core.cpp +12 -0
@@ 7,6 7,8 @@
#include <purefs/blkdev/disk_manager.hpp>
#include <purefs/blkdev/disk_image.hpp>
#include <purefs/fs/drivers/filesystem_vfat.hpp>
#include <purefs/vfs_subsystem.hpp>
#include <purefs/fs/thread_local_cwd.hpp>
#include <sys/statvfs.h>
#include <sys/stat.h>
#include <fcntl.h>


@@ 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);
}