~aleteoryx/muditaos

174fbaa48cf841c084cb4b88b90a4341d8896dac — Lucjan Bryndza 5 years ago c7d9b6e
[EGD-4758] Add Littlefs in the vfscore

Initial concept commit
M module-vfs/CMakeLists.txt => module-vfs/CMakeLists.txt +3 -0
@@ 36,6 36,7 @@ set(FF_FAT_SOURCES
    ${FF_FAT_SOURCES_THIRDPARTY}
    ${CMAKE_CURRENT_SOURCE_DIR}/drivers/src/thirdparty/fatfs/ffsystem.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/drivers/src/thirdparty/fatfs/ff_glue.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/drivers/src/thirdparty/littlefs/lfs_glue.cpp
)




@@ 73,6 74,7 @@ set(SOURCES ""
        src/purefs/fs/filesystem_cwd.cpp
        src/purefs/vfs_subsystem.cpp
        drivers/src/purefs/fs/filesystem_vfat.cpp
        drivers/src/purefs/fs/filesystem_littlefs.cpp
        src/deprecated/vfs-utils.cpp
        src/deprecated/vfs.cpp
        src/deprecated/vfsNotifier.cpp


@@ 119,6 121,7 @@ target_include_directories(${PROJECT_NAME}
target_include_directories(${PROJECT_NAME}
        PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/drivers/include/thirdparty/fatfs
        ${CMAKE_CURRENT_SOURCE_DIR}/drivers/include/thirdparty
        ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/fatfs/source
)


A module-vfs/drivers/include/purefs/fs/drivers/filesystem_littlefs.hpp => module-vfs/drivers/include/purefs/fs/drivers/filesystem_littlefs.hpp +64 -0
@@ 0,0 1,64 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <purefs/fs/filesystem_operations.hpp>

namespace purefs::fs::drivers
{

    /** Filesystem specific driver base class */
    class filesystem_littlefs final : public filesystem_operations
    {
      public:
        using fsfile                                       = std::shared_ptr<internal::file_handle>;
        using fsdir                                        = std::shared_ptr<internal::directory_handle>;
        using fsmount                                      = std::shared_ptr<internal::mount_point>;
        filesystem_littlefs()                              = default;
        filesystem_littlefs(const filesystem_operations &) = delete;
        virtual ~filesystem_littlefs()                     = default;
        auto operator=(const filesystem_operations &) = delete;
        /** Allocate mount point class specify to the VFS
         * @return Allocated mount point structure
         */
        auto mount_prealloc(std::shared_ptr<blkdev::internal::disk_handle> diskh, std::string_view path, unsigned flags)
            -> fsmount override;
        auto mount(fsmount mnt) noexcept -> int override;
        auto umount(fsmount mnt) noexcept -> int override;
        auto stat_vfs(fsmount mnt, std::string_view path, statvfs &stat) const noexcept -> int override;

        /** Standard file access API */
        auto open(fsmount mnt, std::string_view path, int flags, int mode) noexcept -> fsfile override;
        auto close(fsfile zfile) noexcept -> int override;
        auto write(fsfile zfile, const char *ptr, size_t len) noexcept -> ssize_t override;
        auto read(fsfile zfile, char *ptr, size_t len) noexcept -> ssize_t override;
        auto seek(fsfile zfile, off_t pos, int dir) noexcept -> off_t override;
        auto fstat(fsfile zfile, struct stat &st) noexcept -> int override;
        auto stat(fsmount mnt, std::string_view file, struct stat &st) noexcept -> int override;
        auto link(fsmount mnt, std::string_view existing, std::string_view newlink) noexcept -> int override;
        auto symlink(fsmount mnt, std::string_view existing, std::string_view newlink) noexcept -> int override;
        auto unlink(fsmount mnt, std::string_view name) noexcept -> int override;
        auto rename(fsmount mnt, std::string_view oldname, std::string_view newname) noexcept -> int override;
        auto mkdir(fsmount mnt, std::string_view path, int mode) noexcept -> int override;

        /** Directory support API */
        auto diropen(fsmount mnt, std::string_view path) noexcept -> fsdir override;
        auto dirreset(fsdir dirstate) noexcept -> int override;
        auto dirnext(fsdir dirstate, std::string &filename, struct stat &filestat) -> int override;
        auto dirclose(fsdir dirstate) noexcept -> int override;

        /** Other fops API */
        auto ftruncate(fsfile zfile, off_t len) noexcept -> int override;
        auto fsync(fsfile zfile) noexcept -> int override;
        auto ioctl(fsmount mnt, std::string_view path, int cmd, void *arg) noexcept -> int override;
        auto utimens(fsmount mnt, std::string_view path, std::array<timespec, 2> &tv) noexcept -> int override;
        auto flock(fsfile zfile, int cmd) noexcept -> int;
        auto isatty(fsfile zfile) noexcept -> int override;

        auto chmod(fsmount mnt, std::string_view path, mode_t mode) noexcept -> int override;
        auto fchmod(fsfile zfile, mode_t mode) noexcept -> int override;

        auto filesystem_register_completed() const noexcept -> int override;
    };
} // namespace purefs::fs::drivers

A module-vfs/drivers/include/purefs/fs/drivers/mount_point_littlefs.hpp => module-vfs/drivers/include/purefs/fs/drivers/mount_point_littlefs.hpp +39 -0
@@ 0,0 1,39 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#pragma once
#include <purefs/fs/mount_point.hpp>
#include <lfs.h>

namespace purefs::fs::drivers
{

    class mount_point_littlefs final : public purefs::fs::internal::mount_point
    {
      public:
        mount_point_littlefs(std::shared_ptr<blkdev::internal::disk_handle> diskh,
                             std::string_view path,
                             unsigned flags,
                             std::shared_ptr<filesystem_operations> fs)
            : mount_point(diskh, path, flags, fs)
        {}
        virtual ~mount_point_littlefs() = default;

        [[nodiscard]] auto lfs_config() noexcept
        {
            return &m_lfs_conf;
        }
        [[nodiscard]] auto lfs_mount() noexcept
        {
            return &m_lfs_mount;
        }

      private:
        auto native_root() const noexcept -> std::string_view override
        {
            return "/";
        }
        struct lfs_config m_lfs_conf
        {};
        lfs_t m_lfs_mount{};
    };
} // namespace purefs::fs::drivers

M module-vfs/drivers/include/purefs/fs/drivers/mount_point_vfat.hpp => module-vfs/drivers/include/purefs/fs/drivers/mount_point_vfat.hpp +3 -1
@@ 18,7 18,7 @@ namespace purefs::fs::drivers
            : mount_point(diskh, path, flags, fs)
        {}
        virtual ~mount_point_vfat() = default;
        auto fatfs() noexcept
        [[nodiscard]] auto fatfs() noexcept
        {
            return &m_fatfs;
        }


@@ 41,6 41,8 @@ namespace purefs::fs::drivers
        {
            return (m_ff_drive[0] == ' ') ? (-1) : (m_ff_drive[0] - '0');
        }

      private:
        auto native_root() const noexcept -> std::string_view override
        {
            return ff_drive();

A module-vfs/drivers/include/thirdparty/littlefs/volume_mapper.hpp => module-vfs/drivers/include/thirdparty/littlefs/volume_mapper.hpp +33 -0
@@ 0,0 1,33 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <purefs/blkdev/defs.hpp>
#include <memory>

namespace purefs::blkdev
{
    class disk_manager;
}
struct lfs_config;

namespace purefs::fs::drivers::littlefs::internal
{

    /**
     * Append volume and configure LFS
     * @param lfs Lfs structure in the mount point
     * @param diskmm Disk manager
     * @param diskh  Disk handle in manager
     * @return Error code or success
     */
    int append_volume(lfs_config &lfsc, std::shared_ptr<blkdev::disk_manager> diskmm, blkdev::disk_fd diskh);

    /**  Deconfigure volume
     *
     * @param lfsc LFs configuration structure
     */
    void remove_volume(lfs_config &lfsc);

} // namespace purefs::fs::drivers::littlefs::internal

A module-vfs/drivers/src/purefs/fs/filesystem_littlefs.cpp => module-vfs/drivers/src/purefs/fs/filesystem_littlefs.cpp +23 -0
@@ 0,0 1,23 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <purefs/fs/drivers/filesystem_littlefs.hpp>
#include <purefs/fs/drivers/mount_point_littlefs.hpp>
#include <lfs.h>

namespace purefs::fs::drivers
{

    auto filesystem_littlefs::mount_prealloc(std::shared_ptr<blkdev::internal::disk_handle> diskh,
                                             std::string_view path,
                                             unsigned int flags) -> fsmount
    {
        return std::make_shared<mount_point_littlefs>(diskh, path, flags, shared_from_this());
    }

    auto filesystem_littlefs::mount(fsmount mnt) noexcept -> int
    {
        return -1;
    }

} // namespace purefs::fs::drivers

M module-vfs/drivers/src/purefs/fs/filesystem_vfat.cpp => module-vfs/drivers/src/purefs/fs/filesystem_vfat.cpp +1 -1
@@ 8,7 8,7 @@
#include <purefs/fs/drivers/file_handle_vfat.hpp>
#include <purefs/fs/drivers/directory_handle_vfat.hpp>
#include <log/log.hpp>
#include <volume_mapper.hpp>
#include <fatfs/volume_mapper.hpp>
#include <ff.h>
#include <sys/statvfs.h>
#include <limits.h>

A module-vfs/drivers/src/thirdparty/littlefs/lfs_glue.cpp => module-vfs/drivers/src/thirdparty/littlefs/lfs_glue.cpp +142 -0
@@ 0,0 1,142 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <littlefs/volume_mapper.hpp>
#include <lfs.h>
#include <purefs/blkdev/disk_handle.hpp>
#include <purefs/blkdev/disk_manager.hpp>
#include <log/log.hpp>

namespace purefs::fs::drivers::littlefs::internal
{

    // LFS io API
    namespace
    {
        namespace lfs_io
        {

            class io_context
            {
              public:
                io_context(std::shared_ptr<blkdev::disk_manager> diskmm, blkdev::disk_fd diskh, size_t _sector_size)
                    : disk(diskmm), disk_h(diskh), sector_size(_sector_size)
                {}
                const std::weak_ptr<blkdev::disk_manager> disk;
                const blkdev::disk_fd disk_h;
                const size_t sector_size;
            };

            int read(const struct lfs_config *lfsc, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size)
            {
                auto ctx = reinterpret_cast<io_context *>(lfsc->context);
                if (!ctx) {
                    return LFS_ERR_IO;
                }
                auto diskmm = ctx->disk.lock();
                if (!diskmm) {
                    return LFS_ERR_IO;
                }
                const auto lba = (uint64_t(lfsc->block_size) * block + off) / ctx->sector_size;
                if (off % ctx->sector_size) {
                    LOG_ERROR("Partial offset not supported");
                    return LFS_ERR_IO;
                }
                const std::size_t lba_sz = (size * lfsc->block_size) / ctx->sector_size;
                const auto err           = diskmm->read(ctx->disk_h, buffer, lba, lba_sz);
                if (err) {
                    LOG_ERROR("Sector read error %i", err);
                }
                return err;
            }

            int prog(
                const struct lfs_config *lfsc, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size)
            {
                auto ctx = reinterpret_cast<io_context *>(lfsc->context);
                if (!ctx) {
                    return LFS_ERR_IO;
                }
                auto diskmm = ctx->disk.lock();
                if (!diskmm) {
                    return LFS_ERR_IO;
                }
                const auto lba = (uint64_t(lfsc->block_size) * block + off) / ctx->sector_size;
                if (off % ctx->sector_size) {
                    LOG_ERROR("Partial offset not supported");
                    return LFS_ERR_IO;
                }
                const std::size_t lba_sz = (size * lfsc->block_size) / ctx->sector_size;
                const auto err           = diskmm->write(ctx->disk_h, buffer, lba, lba_sz);
                if (err) {
                    LOG_ERROR("Sector read error %i", err);
                }
                return err;
            }

            int erase(const struct lfs_config *lfsc, lfs_block_t block)
            {
                auto ctx = reinterpret_cast<io_context *>(lfsc->context);
                if (!ctx) {
                    return LFS_ERR_IO;
                }
                auto diskmm = ctx->disk.lock();
                if (!diskmm) {
                    return LFS_ERR_IO;
                }
                const auto lba    = (uint64_t(lfsc->block_size) * block) / ctx->sector_size;
                const auto lba_sz = lfsc->block_size / ctx->sector_size;
                int err           = diskmm->erase(ctx->disk_h, lba, lba_sz);
                if (err) {
                    LOG_ERROR("Unable to erase area ret: %i", err);
                }
                return err;
            }

            int sync(const struct lfs_config *lfsc)
            {
                auto ctx = reinterpret_cast<io_context *>(lfsc->context);
                if (!ctx) {
                    return LFS_ERR_IO;
                }
                auto diskmm = ctx->disk.lock();
                if (!diskmm) {
                    return LFS_ERR_IO;
                }
                int err = diskmm->sync(ctx->disk_h);
                if (err) {
                    LOG_ERROR("Unable to sync %i", err);
                }
                return err;
            }
        } // namespace lfs_io
    }     // namespace

    int append_volume(lfs_config &lfsc, std::shared_ptr<blkdev::disk_manager> diskmm, blkdev::disk_fd diskh)
    {
        const auto sect_size = diskmm->get_info(diskh, blkdev::info_type::sector_size);
        if (sect_size < 0) {
            LOG_ERROR("Unable to get sector size %li", sect_size);
            return sect_size;
        }
        if (sect_size % lfsc.block_size || lfsc.block_size < sect_size) {
            LOG_ERROR("Sector size doesn't match block size");
            return -ERANGE;
        }
        auto ctx     = new lfs_io::io_context(diskmm, diskh, sect_size);
        lfsc.context = ctx;
        lfsc.read    = lfs_io::read;
        lfsc.prog    = lfs_io::prog;
        lfsc.erase   = lfs_io::erase;
        lfsc.sync    = lfs_io::sync;
        lfsc.context = ctx;
        return 0;
    }

    void remove_volume(lfs_config &lfsc)
    {
        if (lfsc.context) {
            delete reinterpret_cast<lfs_io::io_context *>(lfsc.context);
        }
    }

} // namespace purefs::fs::drivers::littlefs::internal