~aleteoryx/muditaos

8818b30d1eb47f8638ef3227b16631388930e2ed — Lucjan Bryndza 4 years ago 2a17ec9
[EGD-6075] Add support for emmc system partitions

Add support for EMMC hardware partitions to the
disk manager
Hardware system partitions are visible as <device_name>sys<num>
Disk user partitions are visible as <device_name>part<num>

Signed-off-by: Lucjan Bryndza <lucjan.bryndza@mudita.com>
M enabled_unittests => enabled_unittests +1 -0
@@ 423,6 423,7 @@ TESTS_LIST["catch2-vfs-disk"]="
    Null pointer passed to disk manager functions;
    Boundary checks for partitions;
    Disk sectors out of range for partition;
    Alternative partitions in the disk manager;
"
#---------
TESTS_LIST["catch2-vfs-littlefs"]="

M module-vfs/board/linux/purefs/include/purefs/blkdev/disk_image.hpp => module-vfs/board/linux/purefs/include/purefs/blkdev/disk_image.hpp +15 -9
@@ 1,16 1,21 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <purefs/blkdev/disk.hpp>
#include <mutex>
#include <array>

namespace purefs::blkdev
{
    class disk_image final : public disk
    {
        static constexpr auto sector_size = 512UL;
        static constexpr auto invalid_fd      = -1;
        static constexpr auto syspart_count   = 8U;
        static constexpr auto syspart_size    = 256UL * 1024UL * 1024UL;
        static constexpr auto syspart_sectors = syspart_size / sector_size;

      public:
        disk_image(std::string_view image_filename);


@@ 20,18 25,19 @@ namespace purefs::blkdev
      private:
        auto probe(unsigned flags) -> int override;
        auto cleanup() -> int override;
        auto write(const void *buf, sector_t lba, std::size_t count) -> int override;
        auto read(void *buf, sector_t lba, std::size_t count) -> int override;
        auto write(const void *buf, sector_t lba, std::size_t count, hwpart_t hwpart) -> int override;
        auto read(void *buf, sector_t lba, std::size_t count, hwpart_t hwpart) -> int override;
        auto sync() -> int override;
        auto status() const -> media_status override;
        auto get_info(info_type what) const -> scount_t override;
        auto erase(sector_t lba, std::size_t count) -> int override;
        auto range_valid(sector_t lba, std::size_t count) const -> bool;
        auto get_info(info_type what, hwpart_t hwpart) const -> scount_t override;
        auto erase(sector_t lba, std::size_t count, hwpart_t hwpart) -> int override;
        auto range_valid(sector_t lba, std::size_t count, hwpart_t hwpart) const -> bool;
        auto open_and_truncate(hwpart_t hwpart) -> int;

      private:
        int m_filedes{-1};
        unsigned long m_sectors{0};
        std::string m_image_name;
        std::array<int, syspart_count> m_filedes;
        std::array<unsigned long, syspart_count> m_sectors;
        const std::string m_image_name;
        mutable std::recursive_mutex m_mtx;
    };
} // namespace purefs::blkdev

M module-vfs/board/linux/purefs/src/blkdev/disk_image.cpp => module-vfs/board/linux/purefs/src/blkdev/disk_image.cpp +89 -36
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <purefs/blkdev/disk_image.hpp>
#include <fcntl.h>


@@ 11,49 11,60 @@ namespace purefs::blkdev
{

    disk_image::disk_image(std::string_view image_filename) : m_image_name(image_filename)
    {}
    {
        m_filedes.fill(invalid_fd);
        std::fill(m_sectors.begin() + 1, m_sectors.end(), syspart_sectors);
        m_sectors[0] = 0;
    }

    auto disk_image::probe(unsigned int flags) -> int
    {
        std::lock_guard<std::recursive_mutex> m_lock(m_mtx);
        m_filedes = ::open(m_image_name.c_str(), O_RDWR, O_SYNC);
        if (!m_filedes)
            return m_filedes;
        m_filedes[0] = ::open(m_image_name.c_str(), O_RDWR | O_SYNC);
        if (!m_filedes[0])
            return m_filedes[0];
        struct stat fst;
        auto ret = ::fstat(m_filedes, &fst);
        auto ret = ::fstat(m_filedes[0], &fst);
        if (ret < 0) {
            return -errno;
        }
        m_sectors = fst.st_size / sector_size;
        m_sectors[0] = fst.st_size / sector_size;
        return fst.st_size % sector_size;
    }

    auto disk_image::cleanup() -> int
    {
        std::lock_guard<std::recursive_mutex> m_lock(m_mtx);
        int ret{-EBADFD};
        if (m_filedes) {
            if (m_filedes) {
                ret = ::close(m_filedes);
        int ret{};
        for (auto &fd : m_filedes)
            if (fd > 0) {
                ret = ::close(fd);
                if (ret < 0)
                    ret = -errno;
                    return -errno;
                else
                    fd = invalid_fd;
            }
        }
        return ret;
    }
    auto disk_image::write(const void *buf, sector_t lba, std::size_t count) -> int

    auto disk_image::write(const void *buf, sector_t lba, std::size_t count, hwpart_t hwpart) -> int
    {
        std::lock_guard<std::recursive_mutex> m_lock(m_mtx);
        if (!range_valid(lba, count)) {
        if (!range_valid(lba, count, hwpart)) {
            return -ERANGE;
        }
        auto offs = ::lseek64(m_filedes, off64_t(lba) * off64_t(sector_size), SEEK_SET);
        const int err = open_and_truncate(hwpart);
        if (err) {
            return err;
        }
        auto offs = ::lseek64(m_filedes[hwpart], off64_t(lba) * off64_t(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 {
            auto ret = ::write(m_filedes, buf_b, to_write);
            auto ret = ::write(m_filedes[hwpart], buf_b, to_write);
            if (ret < 0) {
                return -errno;
            }


@@ 62,26 73,32 @@ namespace purefs::blkdev
        } while (to_write > 0);
        return 0;
    }
    auto disk_image::erase(sector_t lba, std::size_t count) -> int

    auto disk_image::erase(sector_t lba, std::size_t count, hwpart_t hwpart) -> int
    {
        std::unique_ptr<char[]> buf(new char[count * sector_size]);
        std::memset(buf.get(), 0xff, count * sector_size);
        return write(buf.get(), lba, count);
        return write(buf.get(), lba, count, hwpart);
    }
    auto disk_image::read(void *buf, sector_t lba, std::size_t count) -> int

    auto disk_image::read(void *buf, sector_t lba, std::size_t count, hwpart_t hwpart) -> int
    {
        std::lock_guard<std::recursive_mutex> m_lock(m_mtx);
        if (!range_valid(lba, count)) {
        if (!range_valid(lba, count, hwpart)) {
            return -ERANGE;
        }
        auto offs = ::lseek64(m_filedes, off64_t(lba) * off64_t(sector_size), SEEK_SET);
        const int err = open_and_truncate(hwpart);
        if (err) {
            return err;
        }
        auto offs = ::lseek64(m_filedes[hwpart], off64_t(lba) * off64_t(sector_size), SEEK_SET);
        if (offs < 0) {
            return offs;
        }
        auto to_read = count * sector_size;
        auto buf_b   = reinterpret_cast<uint8_t *>(buf);
        do {
            auto ret = ::read(m_filedes, buf_b, to_read);
            auto ret = ::read(m_filedes[hwpart], buf_b, to_read);
            if (ret < 0) {
                return -errno;
            }


@@ 90,42 107,78 @@ namespace purefs::blkdev
        } while (to_read > 0);
        return 0;
    }

    auto disk_image::sync() -> int
    {
        std::lock_guard<std::recursive_mutex> m_lock(m_mtx);
        int ret{-EBADFD};
        if (m_filedes) {
            ret = fsync(m_filedes);
            if (ret < 0)
                ret = -errno;
        }
        int ret{};
        for (auto fd : m_filedes)
            if (fd > 0) {
                ret = fsync(fd);
                if (ret < 0)
                    return -errno;
            }
        return ret;
    }

    auto disk_image::status() const -> media_status
    {
        std::lock_guard<std::recursive_mutex> m_lock(m_mtx);
        struct stat st;
        auto ret = ::stat(m_image_name.c_str(), &st);
        if (!ret)
        const auto ret = ::stat(m_image_name.c_str(), &st);
        if (ret < 0)
            return media_status::nomedia;
        else
            return media_status::healthly;
    }
    auto disk_image::get_info(info_type what) const -> scount_t

    auto disk_image::get_info(info_type what, hwpart_t hwpart) const -> scount_t
    {
        std::lock_guard<std::recursive_mutex> m_lock(m_mtx);
        if (hwpart >= syspart_count) {
            return -ERANGE;
        }
        switch (what) {
        case info_type::sector_size:
            return sector_size;
        case info_type::sector_count:
            return m_sectors;
            return m_sectors[hwpart];
        case info_type::erase_block:
            return 1;
        }
        return -1;
        return -ENOTSUP;
    }
    auto disk_image::range_valid(sector_t lba, std::size_t count) const -> bool

    auto disk_image::range_valid(sector_t lba, std::size_t count, hwpart_t hwpart) const -> bool
    {
        return (lba < m_sectors) && ((lba + count) < m_sectors);
        return (hwpart < syspart_count) && (lba < m_sectors[hwpart]) && ((lba + count) < m_sectors[hwpart]);
    }

    auto disk_image::disk_image::open_and_truncate(hwpart_t hwpart) -> int
    {
        if (hwpart >= syspart_count) {
            return -ERANGE;
        }
        if (hwpart == 0 || m_filedes[hwpart] > 0) {
            return 0;
        }
        using namespace std::string_literals;
        const auto alt_filename = m_image_name + "."s + std::to_string(hwpart);
        m_filedes[hwpart]       = ::open(alt_filename.c_str(), O_RDWR | O_CREAT | O_SYNC, 0644);
        if (m_filedes[hwpart] < 0) {
            return -errno;
        }
        struct stat fst;
        auto ret = ::fstat(m_filedes[hwpart], &fst);
        if (ret < 0) {
            return -errno;
        }
        if (static_cast<unsigned long>(fst.st_size) < m_sectors[hwpart] * sector_size) {
            ret = ::ftruncate(m_filedes[hwpart], syspart_size);
            if (ret < 0) {
                return ret;
            }
        }
        return 0;
    }
} // namespace purefs::blkdev

M module-vfs/board/rt1051/purefs/include/purefs/blkdev/disk_emmc.hpp => module-vfs/board/rt1051/purefs/include/purefs/blkdev/disk_emmc.hpp +9 -4
@@ 6,6 6,7 @@
#include <purefs/blkdev/disk.hpp>
#include <mutex.hpp>
#include <memory>
#include <atomic>

#if !defined(TARGET_RT1051)
static_assert(false, "Unsupported target.");


@@ 26,16 27,20 @@ namespace purefs::blkdev

        auto probe(unsigned flags) -> int override;
        auto cleanup() -> int override;
        auto write(const void *buf, sector_t lba, std::size_t count) -> int override;
        auto read(void *buf, sector_t lba, std::size_t count) -> int override;
        auto write(const void *buf, sector_t lba, std::size_t count, hwpart_t hwpart) -> int override;
        auto read(void *buf, sector_t lba, std::size_t count, hwpart_t hwpart) -> int override;
        auto sync() -> int override;
        auto status() const -> media_status override;
        auto get_info(info_type what) const -> scount_t override;
        auto erase(sector_t lba, std::size_t count) -> int override;
        auto get_info(info_type what, hwpart_t hwpart) const -> scount_t override;
        auto erase(sector_t lba, std::size_t count, hwpart_t hwpart) -> int override;

      private:
        auto switch_partition(hwpart_t newpart) -> int;

      private:
        int initStatus;
        std::unique_ptr<_mmc_card> mmcCard;
        mutable cpp_freertos::MutexRecursive mutex;
        std::atomic<hwpart_t> currHwPart{0};
    };
} // namespace purefs::blkdev

M module-vfs/board/rt1051/purefs/src/blkdev/disk_emmc.cpp => module-vfs/board/rt1051/purefs/src/blkdev/disk_emmc.cpp +43 -8
@@ 47,32 47,40 @@ namespace purefs::blkdev
        return statusBlkDevSuccess;
    }

    auto disk_emmc::write(const void *buf, sector_t lba, std::size_t count) -> int
    auto disk_emmc::write(const void *buf, sector_t lba, std::size_t count, hwpart_t hwpart) -> int
    {
        cpp_freertos::LockGuard lock(mutex);
        if (!mmcCard->isHostReady || buf == nullptr) {
            return statusBlkDevFail;
        }
        auto err = MMC_WriteBlocks(mmcCard.get(), static_cast<const uint8_t *>(buf), lba, count);
        auto err = switch_partition(hwpart);
        if (err != kStatus_Success) {
            return err;
        }
        err = MMC_WriteBlocks(mmcCard.get(), static_cast<const uint8_t *>(buf), lba, count);
        if (err != kStatus_Success) {
            return err;
        }
        return statusBlkDevSuccess;
    }

    auto disk_emmc::erase(sector_t lba, std::size_t count) -> int
    auto disk_emmc::erase(sector_t lba, std::size_t count, hwpart_t hwpart) -> int
    {
        // erase group size is 512kB so it has been deliberately disallowed
        // group of this size would make the solution inefficient in this case
        return statusBlkDevSuccess;
    }
    auto disk_emmc::read(void *buf, sector_t lba, std::size_t count) -> int
    auto disk_emmc::read(void *buf, sector_t lba, std::size_t count, hwpart_t hwpart) -> int
    {
        cpp_freertos::LockGuard lock(mutex);
        if (!mmcCard->isHostReady || buf == nullptr) {
            return statusBlkDevFail;
        }
        auto err = MMC_ReadBlocks(mmcCard.get(), static_cast<uint8_t *>(buf), lba, count);
        auto err = switch_partition(hwpart);
        if (err != kStatus_Success) {
            return err;
        }
        err = MMC_ReadBlocks(mmcCard.get(), static_cast<uint8_t *>(buf), lba, count);
        if (err != kStatus_Success) {
            return err;
        }


@@ 110,18 118,45 @@ namespace purefs::blkdev
        return media_status::healthly;
    }

    auto disk_emmc::get_info(info_type what) const -> scount_t
    auto disk_emmc::get_info(info_type what, hwpart_t hwpart) const -> scount_t
    {
        cpp_freertos::LockGuard lock(mutex);
        switch (what) {
        case info_type::sector_size:
            return mmcCard->blockSize;
        case info_type::sector_count:
            return mmcCard->userPartitionBlocks;
            switch (hwpart) {
            case kMMC_AccessPartitionUserArea:
                return mmcCard->userPartitionBlocks;
            case kMMC_AccessPartitionBoot1:
            case kMMC_AccessPartitionBoot2:
                return mmcCard->bootPartitionBlocks;
            default:
                return mmcCard->systemPartitionBlocks;
            }
        case info_type::erase_block:
            // not supported
            return 0;
        }
        return -1;
        return -ENOTSUP;
    }

    auto disk_emmc::switch_partition(hwpart_t newpart) -> int
    {
        if (newpart > kMMC_AccessGeneralPurposePartition4) {
            return -ERANGE;
        }
        int ret{};
        if (newpart != currHwPart) {
            ret = MMC_SelectPartition(mmcCard.get(), static_cast<mmc_access_partition_t>(newpart));
            if (ret == kStatus_Success) {
                currHwPart = newpart;
            }
            else {
                LOG_ERROR("Unable to switch partition err %i", ret);
            }
        }
        return ret;
    }

} // namespace purefs::blkdev

M module-vfs/include/internal/purefs/blkdev/disk_handle.hpp => module-vfs/include/internal/purefs/blkdev/disk_handle.hpp +36 -5
@@ 5,6 5,7 @@

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

namespace purefs::blkdev


@@ 17,11 18,41 @@ namespace purefs::blkdev::internal

    class disk_handle
    {
        static constexpr part_t no_partition     = -1;
        static constexpr auto hw_partition_first = std::numeric_limits<part_t>::max() / 2;

      public:
        static constexpr auto no_partition = -1;
        explicit disk_handle(std::weak_ptr<blkdev::disk> disk, std::string_view name, short partition = no_partition)
        static constexpr auto to_syspart_num(part_t part) -> part_t
        {
            return part + hw_partition_first;
        }
        static auto is_any_partition(part_t part) noexcept -> bool
        {
            return part >= 0;
        }
        static auto is_system_partition(part_t part) noexcept -> bool
        {
            return part >= hw_partition_first;
        }
        static auto is_user_partition(part_t part) noexcept -> bool
        {
            return is_any_partition(part) && !is_system_partition(part);
        }
        explicit disk_handle(std::weak_ptr<blkdev::disk> disk, std::string_view name, part_t partition = no_partition)
            : m_disk(disk), m_partition(partition), m_name(name)
        {}
        auto is_any_partition() const noexcept -> bool
        {
            return is_any_partition(m_partition);
        }
        auto is_system_partition() const noexcept -> bool
        {
            return is_system_partition(m_partition);
        }
        auto is_user_partition() const noexcept -> bool
        {
            return is_user_partition(m_partition);
        }
        auto disk() const noexcept
        {
            return m_disk.lock();


@@ 30,9 61,9 @@ namespace purefs::blkdev::internal
        {
            return m_partition;
        }
        auto has_partition() const noexcept -> bool
        auto system_partition() const noexcept -> int
        {
            return m_partition != no_partition;
            return (m_partition >= hw_partition_first) ? (m_partition - hw_partition_first + 1) : (0);
        }
        auto sectors() const noexcept -> sector_t;
        auto name() const noexcept


@@ 42,7 73,7 @@ namespace purefs::blkdev::internal

      private:
        const std::weak_ptr<blkdev::disk> m_disk;
        const short m_partition{-1};
        const part_t m_partition{no_partition};
        mutable sector_t m_sectors{0};
        const std::string m_name;
    };

M module-vfs/include/user/purefs/blkdev/defs.hpp => module-vfs/include/user/purefs/blkdev/defs.hpp +9 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 7,8 7,16 @@

namespace purefs::blkdev
{
    //! Unsigned sector type
    using sector_t = uint64_t;
    //! Signed sector type
    using scount_t = int64_t;
    //! Hardware partition type
    using hwpart_t = uint8_t;
    //! Common partition type
    using part_t = int16_t;
    //! Default hardware partition
    constexpr hwpart_t default_hw_partition = 0;
    namespace internal
    {
        class disk_handle;

M module-vfs/include/user/purefs/blkdev/disk.hpp => module-vfs/include/user/purefs/blkdev/disk.hpp +12 -9
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 11,9 11,9 @@ namespace purefs::blkdev
    class disk
    {
      public:
        disk()             = default;
        disk(const disk &) = delete;
        auto operator=(const disk &) = delete;
        disk()                       = default;
        virtual ~disk()              = default;

        /** Initialize the disk this method is called by the disc manager


@@ 30,25 30,28 @@ namespace purefs::blkdev
        /** Write a data onto block device or partition
         * @param[in] buf Data buffer to write
         * @param[in] lba First sector
         * @param[in] Count sectors count
         * @param[in] count sectors count
         * @param[in] hwpart Hardware partition
         * @return zero on success otherwise error
         */
        virtual auto write(const void *buf, sector_t lba, std::size_t count) -> int = 0;
        virtual auto write(const void *buf, sector_t lba, std::size_t count, hwpart_t hwpart) -> int = 0;

        /** Read a data from block device or partition
         * @param[in] buf Data buffer for read
         * @param[in] lba First sector
         * @param[in] Count sectors count
         * @param[in] count sectors count
         * @param[in] hwpart Hardware partition
         * @return zero on success otherwise error
         */
        virtual auto read(void *buf, sector_t lba, std::size_t count) -> int = 0;
        virtual auto read(void *buf, sector_t lba, std::size_t count, hwpart_t hwpart) -> int = 0;

        /** Erase selected area on the block device or partition
         * @param[in] lba First sector to erase
         * @param[in] count Sectors count for erase
         * @param[in] hwpart Hardware partition
         * @return zero or success otherwise error
         */
        virtual auto erase(sector_t lba, std::size_t count) -> int;
        virtual auto erase(sector_t lba, std::size_t count, hwpart_t hwpart) -> int;

        /** Flush buffers and write all data into the physical device
         * @return zero or success otherwise error


@@ 77,9 80,10 @@ namespace purefs::blkdev

        /** List the partitions on the underlaying device
         * @param[in] device_name Block device name
         * @param[in] hwpart Hardware partition
         * @return Partition list @see partition
         */
        [[nodiscard]] virtual auto get_info(info_type what) const -> scount_t = 0;
        [[nodiscard]] virtual auto get_info(info_type what, hwpart_t hwpart) const -> scount_t = 0;

        /** List the partitions on the underlaying device
         * @param[in] device_name Block device name


@@ 90,7 94,6 @@ namespace purefs::blkdev
            return m_partitions;
        }

      protected:
        /** Clear all partitions */
        auto clear_partitions() -> void
        {

M module-vfs/include/user/purefs/blkdev/disk_manager.hpp => module-vfs/include/user/purefs/blkdev/disk_manager.hpp +2 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 139,7 139,7 @@ namespace purefs::blkdev
        static auto disk_handle_from_partition_handle(disk_fd disk) -> disk_fd;

      private:
        static auto parse_device_name(std::string_view device) -> std::tuple<std::string_view, short>;
        static auto parse_device_name(std::string_view device) -> std::tuple<std::string_view, part_t>;
        static auto part_lba_to_disk_lba(disk_fd disk, sector_t part_lba, size_t count) -> scount_t;

      private:

M module-vfs/src/purefs/blkdev/disk.cpp => module-vfs/src/purefs/blkdev/disk.cpp +2 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <purefs/blkdev/disk.hpp>


@@ 6,7 6,7 @@

namespace purefs::blkdev
{
    auto disk::erase(sector_t lba, std::size_t count) -> int
    auto disk::erase(sector_t lba, std::size_t count, hwpart_t hwpart) -> int
    {
        return -ENOTSUP;
    }

M module-vfs/src/purefs/blkdev/disk_handle.cpp => module-vfs/src/purefs/blkdev/disk_handle.cpp +2 -2
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <purefs/blkdev/disk_handle.hpp>
#include <purefs/blkdev/disk.hpp>


@@ 11,7 11,7 @@ namespace purefs::blkdev::internal
        if (!m_sectors) {
            auto pdisk = m_disk.lock();
            if (pdisk) {
                const auto sector_count = pdisk->get_info(info_type::sector_count);
                const auto sector_count = pdisk->get_info(info_type::sector_count, system_partition());
                if (sector_count > 0) {
                    m_sectors = sector_count;
                }

M module-vfs/src/purefs/blkdev/disk_manager.cpp => module-vfs/src/purefs/blkdev/disk_manager.cpp +36 -26
@@ 19,6 19,7 @@ namespace purefs::blkdev
    {
        using namespace std::literals;
        static constexpr auto part_suffix = "part"sv;
        static constexpr auto syspart_suffix = "sys"sv;
    } // namespace

    disk_manager::disk_manager() : m_lock(std::make_unique<cpp_freertos::MutexRecursive>())


@@ 80,7 81,7 @@ namespace purefs::blkdev
            }
            else {
                ret = std::make_shared<internal::disk_handle>(it->second, device_name, part);
                if (part != internal::disk_handle::no_partition) {
                if (internal::disk_handle::is_user_partition(part)) {
                    if (part >= int(partitions(ret).size())) {
                        LOG_ERROR("Partition %i doesn't exists", part);
                        ret = nullptr;


@@ 91,19 92,26 @@ namespace purefs::blkdev
        return ret;
    }

    auto disk_manager::parse_device_name(std::string_view device) -> std::tuple<std::string_view, short>
    auto disk_manager::parse_device_name(std::string_view device) -> std::tuple<std::string_view, part_t>
    {
        auto ret = device.rfind(part_suffix);
        if (ret != std::string::npos) {
            auto part_name = device.substr(0, ret);
            auto part_num  = device.substr(ret + part_suffix.length());
            short part_inum{-1};
        const auto parti    = device.rfind(part_suffix);
        const auto sysparti = device.rfind(syspart_suffix);
        if ((parti != std::string::npos) != (sysparti != std::string::npos)) {
            const auto si        = (parti != std::string::npos) ? (parti) : (sysparti);
            const auto sl        = (parti != std::string::npos) ? (part_suffix.length()) : (syspart_suffix.length());
            const auto part_name = device.substr(0, si);
            const auto part_num  = device.substr(si + sl);
            part_t part_inum{-1};
            if (!part_num.empty()) {
                auto ires = std::from_chars(std::begin(part_num), std::end(part_num), part_inum);
                if (ires.ec == std::errc())
                const auto ires = std::from_chars(std::begin(part_num), std::end(part_num), part_inum);
                if (ires.ec == std::errc()) {
                    if (sysparti != std::string::npos)
                        part_inum = internal::disk_handle::to_syspart_num(part_inum);
                    return std::make_tuple(part_name, part_inum);
                else
                }
                else {
                    return std::make_tuple(""sv, -1);
                }
            }
            else {
                return std::make_tuple(part_name, part_inum);


@@ 115,18 123,10 @@ namespace purefs::blkdev
    }
    auto disk_manager::part_lba_to_disk_lba(disk_fd disk, sector_t part_lba, size_t count) -> scount_t
    {
        if (!disk->has_partition()) {
            if (part_lba + count > disk->sectors()) {
                LOG_ERROR("Disk sector req out of range");
                return -ERANGE;
            }
            else {
                return part_lba;
            }
        }
        else {
        if (disk->is_user_partition()) {
            auto pdisc = disk->disk();
            if (!pdisc) {
                LOG_ERROR("Unable to lock disk");
                return -EIO;
            }
            const auto part = pdisc->partitions()[disk->partition()];


@@ 138,6 138,15 @@ namespace purefs::blkdev
                return part_lba + part.start_sector;
            }
        }
        else {
            if (part_lba + count > disk->sectors()) {
                LOG_ERROR("Disk sector req out of range");
                return -ERANGE;
            }
            else {
                return part_lba;
            }
        }
    }
    auto disk_manager::write(disk_fd dfd, const void *buf, sector_t lba, std::size_t count) -> int
    {


@@ 155,7 164,7 @@ namespace purefs::blkdev
            return calc_lba;
        }
        else {
            return disk->write(buf, calc_lba, count);
            return disk->write(buf, calc_lba, count, dfd->system_partition());
        }
    }
    auto disk_manager::read(disk_fd dfd, void *buf, sector_t lba, std::size_t count) -> int


@@ 174,7 183,7 @@ namespace purefs::blkdev
            return calc_lba;
        }
        else {
            return disk->read(buf, calc_lba, count);
            return disk->read(buf, calc_lba, count, dfd->system_partition());
        }
    }
    auto disk_manager::erase(disk_fd dfd, sector_t lba, std::size_t count) -> int


@@ 193,7 202,7 @@ namespace purefs::blkdev
            return calc_lba;
        }
        else {
            return disk->erase(calc_lba, count);
            return disk->erase(calc_lba, count, dfd->system_partition());
        }
    }
    auto disk_manager::sync(disk_fd dfd) -> int


@@ 272,7 281,7 @@ namespace purefs::blkdev
            LOG_ERROR("Disk doesn't exists");
            return std::nullopt;
        }
        if (dfd->has_partition()) {
        if (dfd->is_user_partition()) {
            auto parts = disk->partitions();
            if (size_t(dfd->partition()) >= parts.size()) {
                LOG_ERROR("Partition num out of range");


@@ 299,7 308,7 @@ namespace purefs::blkdev
            return {};
        }
        //! When it is partition as for partition sectors count
        if (what == info_type::sector_count && dfd->has_partition()) {
        if (what == info_type::sector_count && dfd->is_user_partition()) {
            if (unsigned(dfd->partition()) >= disk->partitions().size()) {
                LOG_ERROR("Partition number out of range");
                return -ERANGE;


@@ 308,7 317,7 @@ namespace purefs::blkdev
            return part.num_sectors;
        }
        else {
            return disk->get_info(what);
            return disk->get_info(what, dfd->system_partition());
        }
    }
    auto disk_manager::reread_partitions(disk_fd dfd) -> int


@@ 322,6 331,7 @@ namespace purefs::blkdev
            LOG_ERROR("Disk doesn't exists");
            return {};
        }
        disk->clear_partitions();
        internal::partition_parser pparser(disk, disk->partitions());
        auto ret = pparser.partition_search();
        // Fill the partition name

M module-vfs/src/purefs/blkdev/partition_parser.cpp => module-vfs/src/purefs/blkdev/partition_parser.cpp +7 -7
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <purefs/blkdev/partition_parser.hpp>


@@ 48,13 48,13 @@ namespace purefs::blkdev::internal
    // Partition search
    auto partition_parser::partition_search() -> int
    {
        const auto sect_size = m_disk->get_info(info_type::sector_size);
        const auto sect_size = m_disk->get_info(info_type::sector_size, 0);
        if (sect_size < 0) {
            LOG_ERROR("Unable to get sector size");
            return sect_size;
        }
        std::vector<std::uint8_t> mbr_sect(sect_size);
        auto ret = m_disk->read(mbr_sect.data(), 0, 1);
        auto ret = m_disk->read(mbr_sect.data(), 0, 1, 0);
        if (ret < 0) {
            return ret;
        }


@@ 94,8 94,8 @@ namespace purefs::blkdev::internal

    auto partition_parser::check_partition(const std::shared_ptr<disk> disk, const partition &part) -> bool
    {
        auto sector_size     = disk->get_info(info_type::sector_size);
        const auto this_size = uint64_t(disk->get_info(info_type::sector_count)) * uint64_t(sector_size);
        auto sector_size     = disk->get_info(info_type::sector_size, 0);
        const auto this_size = uint64_t(disk->get_info(info_type::sector_count, 0)) * uint64_t(sector_size);
        const auto poffset   = uint64_t(part.start_sector) * uint64_t(sector_size);
        const auto psize     = uint64_t(part.num_sectors) * uint64_t(sector_size);
        const auto pnext     = uint64_t(part.start_sector) * uint64_t(sector_size) + poffset;


@@ 133,7 133,7 @@ namespace purefs::blkdev::internal
    auto partition_parser::parse_extended(uint32_t lba, uint32_t count) -> int
    {
        static constexpr auto max_parts{100};
        auto sector_size = m_disk->get_info(info_type::sector_size);
        auto sector_size = m_disk->get_info(info_type::sector_size, 0);
        int extended_part_num;
        std::array<partition, defs::num_parts> parts;
        auto current_sector     = lba;


@@ 149,7 149,7 @@ namespace purefs::blkdev::internal
        while (try_count--) {
            if (sector_in_buf != current_sector) {
                LOG_INFO("extended parse: Read sector %u\n", unsigned(current_sector));
                error = m_disk->read(sect_buf.data(), current_sector, 1);
                error = m_disk->read(sect_buf.data(), current_sector, 1, 0);
                if (error < 0)
                    break;
                sector_in_buf = current_sector;

M module-vfs/tests/unittest_disk_manager.cpp => module-vfs/tests/unittest_disk_manager.cpp +32 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#define CATCH_CONFIG_MAIN
#include <catch2/catch.hpp>


@@ 105,6 105,37 @@ TEST_CASE("RW boundary checking")
    REQUIRE(buf1 == buf2);
}

TEST_CASE("Alternative partitions in the disk manager")
{
    using namespace purefs;
    blkdev::disk_manager dm;
    auto disk = std::make_shared<blkdev::disk_image>(disk_image);
    REQUIRE(disk);
    REQUIRE(dm.register_device(disk, "emmc0") == 0);
    const auto sect_size  = dm.get_info("emmc0", blkdev::info_type::sector_size);
    const auto sect_size1 = dm.get_info("emmc0sys1", blkdev::info_type::sector_size);
    REQUIRE(sect_size > 0);
    REQUIRE(sect_size == sect_size1);
    const auto sect_count = dm.get_info("emmc0sys1", blkdev::info_type::sector_count);
    REQUIRE(sect_count == (256L * 1024L * 1024L) / sect_size);
    const auto sect_count1 = dm.get_info("emmc0", blkdev::info_type::sector_count);
    REQUIRE(sect_count1 > sect_count);
    std::vector<char> buf1(sect_size, 0);
    REQUIRE(dm.read("emmc0", buf1.data(), 0, 1) == 0);
    std::vector<char> buf2(sect_size, 0xAA);
    REQUIRE(dm.write("emmc0sys1", buf2.data(), 0, 1) == 0);
    std::fill(std::begin(buf2), std::end(buf2), 0xBB);
    REQUIRE(dm.write("emmc0sys0", buf2.data(), 0, 1) == 0);
    REQUIRE(dm.read("emmc0", buf2.data(), 0, 1) == 0);
    REQUIRE(buf1 == buf2);
    std::fill(std::begin(buf2), std::end(buf2), 0xAA);
    REQUIRE(dm.read("emmc0sys1", buf1.data(), 0, 1) == 0);
    REQUIRE(buf1 == buf2);
    std::fill(std::begin(buf2), std::end(buf2), 0xBB);
    REQUIRE(dm.read("emmc0sys0", buf1.data(), 0, 1) == 0);
    REQUIRE(buf1 == buf2);
}

TEST_CASE("Null pointer passed to disk manager functions")
{
    using namespace purefs;