~aleteoryx/muditaos

436c2ed3cc1defc2d415b2b918da6b1d4d861abb — Lucjan Bryndza 5 years ago 4614846
[EGD-5609] Fix lfs partition erase size bug

Storing LFS erase size in the boot byte is not possible
because Linux kernel is unable to detect the partitions
after change boot bytes to values other than 0x80 or 0x00

In this patch LFS_BLOCK_SIZE is moved to the second
MBR bootcode AREA
M host-tools/genlittlefs/lfs_ioaccess.c => host-tools/genlittlefs/lfs_ioaccess.c +4 -0
@@ 171,6 171,7 @@ struct lfs_ioaccess_context *lfs_ioaccess_open(struct lfs_config *cfg,
    }
    ret->file_des = open(filename, O_RDWR);
    if (ret->file_des < 0) {
        free((void *)ret->empty_flash_mem);
        free(ret);
        return NULL;
    }


@@ 178,6 179,7 @@ struct lfs_ioaccess_context *lfs_ioaccess_open(struct lfs_config *cfg,
    int err = fstat(ret->file_des, &statbuf);
    if (err < 0) {
        close(ret->file_des);
        free((void *)ret->empty_flash_mem);
        free(ret);
        return NULL;
    }


@@ 186,6 188,7 @@ struct lfs_ioaccess_context *lfs_ioaccess_open(struct lfs_config *cfg,
        err = ioctl(ret->file_des, BLKGETSIZE64, &blk_size);
        if (err < 0) {
            close(ret->file_des);
            free((void *)ret->empty_flash_mem);
            free(ret);
            return NULL;
        }


@@ 199,6 202,7 @@ struct lfs_ioaccess_context *lfs_ioaccess_open(struct lfs_config *cfg,
    if (partition) {
        if (partition->end > statbuf.st_size) {
            close(ret->file_des);
            free((void *)ret->empty_flash_mem);
            free(ret);
            errno = E2BIG;
            return NULL;

M host-tools/genlittlefs/mklfs.c => host-tools/genlittlefs/mklfs.c +4 -1
@@ 308,6 308,7 @@ int main(int argc, char **argv)
        err = ftruncate(fds, lopts.filesystem_size);
        if (err) {
            perror("Unable to truncate file");
            close(fds);
            free(lopts.src_dirs);
            return EXIT_FAILURE;
        }


@@ 364,6 365,7 @@ int main(int argc, char **argv)
            return EXIT_FAILURE;
        }
    }
    const lfs_ssize_t used_blocks = lfs_fs_size(&lfs);
    err = lfs_unmount(&lfs);
    if (err < 0) {
        fprintf(stderr, "lfs umount error: error=%d\n", err);


@@ 375,11 377,12 @@ int main(int argc, char **argv)
    lfs_ioaccess_close(ioctx);
    printf("Littlefs summary:\n"
           "     Directories created: %lu, Files added: %lu, Transferred %lu kbytes.\n"
           "     Littlefs block size: %i blocks count: %i.\n",
           "     Littlefs block size: %i blocks: %i/%i.\n",
           prog_summary.directories_added,
           prog_summary.files_added,
           prog_summary.bytes_transferred / 1024UL,
           cfg.block_size,
           used_blocks,
           cfg.block_count);
    return EXIT_SUCCESS;
}

M host-tools/genlittlefs/parse_partitions.c => host-tools/genlittlefs/parse_partitions.c +45 -21
@@ 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 <blkid.h>
#include "parse_partitions.h"


@@ 6,10 6,14 @@
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <fcntl.h>
#include <unistd.h>
static const size_t sector_size = 512;
static const size_t part_offset = 446;
static const size_t part_size   = 16;
static const size_t bootstrap_offset = 0x00E0;

struct partition *find_partitions(const char *filename, part_type_t ptype, size_t *nelems)
{


@@ 80,35 84,55 @@ static inline unsigned calculate_shift(uint32_t v)
    return mult_bruijn_bit_position[(uint32_t)(v * 0x07C4ACDDU) >> 27];
}

static ssize_t sector_block_size(int filedes)
{
    struct stat statbuf;
    int err = fstat(filedes, &statbuf);
    if (err < 0) {
        return err;
    }
    uint64_t blk_sz;
    if (S_ISBLK(statbuf.st_mode)) {
        err = ioctl(filedes, BLKSSZGET, &blk_sz);
        if (err < 0) {
            return err;
        }
    }
    else {
        blk_sz = 512;
    }
    return blk_sz;
}

int write_partition_bootunit(const char *filename, int part_num, uint32_t block_size)
{
    if (!filename) {
        errno = EINVAL;
        return -1;
    }
    const uint8_t boot    = calculate_shift(block_size);
    const loff_t fil_offs = part_offset + (part_num - 1) * part_size;
    FILE *fil             = fopen(filename, "r+");
    if (!fil) {
        return -1;
    }
    if (fseek(fil, fil_offs, SEEK_SET) < 0) {
        fclose(fil);
    const int fd = open(filename, O_RDWR);
    if (fd < 0) {
        return -1;
    }
    uint8_t boot_rd;
    if (fread(&boot_rd, sizeof boot_rd, 1, fil) != 1) {
        fclose(fil);
    const ssize_t sector_size = sector_block_size(fd);
    char *const sect_buf      = malloc(sector_size);
    if (read(fd, sect_buf, sector_size) != sector_size) {
        close(fd);
        free(sect_buf);
        return -1;
    }
    if (fseek(fil, fil_offs, SEEK_SET) < 0) {
        fclose(fil);
    const uint8_t log2_block_size         = calculate_shift(block_size);
    sect_buf[bootstrap_offset + part_num] = log2_block_size;
    if (lseek(fd, 0, SEEK_SET) < 0) {
        close(fd);
        free(sect_buf);
        return -1;
    }
    uint8_t boot_wr = (boot_rd & 0x80) | (boot & 0x7f);
    if (fwrite(&boot_wr, sizeof boot_wr, 1, fil) != 1) {
        fclose(fil);
    if (write(fd, sect_buf, sector_size) != sector_size) {
        close(fd);
        free(sect_buf);
        return -1;
    }
    return fclose(fil);
    free(sect_buf);
    return close(fd);
}

M module-vfs/src/newlib/vfs_io_syscalls.cpp => module-vfs/src/newlib/vfs_io_syscalls.cpp +7 -1
@@ 355,7 355,13 @@ namespace vfsn::internal::syscalls
              unsigned long int rwflag,
              const void *data)
    {
        return invoke_fs(_errno_, &purefs::fs::filesystem::mount, special_file, dir, fstype, rwflag, data);
        return invoke_fs(_errno_,
                         &purefs::fs::filesystem::mount,
                         special_file ? special_file : "",
                         dir ? dir : "",
                         fstype ? fstype : "",
                         rwflag,
                         data);
    }

} // namespace vfsn::internal::syscalls

M module-vfs/src/purefs/blkdev/partition_parser.cpp => module-vfs/src/purefs/blkdev/partition_parser.cpp +7 -7
@@ 94,13 94,13 @@ 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);
        unsigned long this_size = disk->get_info(info_type::sector_count) * sector_size;
        const auto poffset      = part.start_sector * sector_size;
        const auto psize        = part.num_sectors * sector_size;
        const auto pnext        = part.start_sector * sector_size + poffset;
        if ((poffset + psize > this_size) ||                                      // oversized
            (pnext < static_cast<unsigned long>(part.start_sector * sector_size)) // going backward
        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);
        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;
        if ((poffset + psize > this_size) ||                    // oversized
            (pnext < uint64_t(part.start_sector) * sector_size) // going backward
        ) {
            LOG_WARN("Part %d looks strange: start_sector %u offset %u next %u\n",
                     unsigned(part.mbr_number),

M module-vfs/src/purefs/fs/filesystem.cpp => module-vfs/src/purefs/fs/filesystem.cpp +2 -2
@@ 55,7 55,7 @@ namespace purefs::fs
        cpp_freertos::LockGuard _lck(*m_lock);
        const auto it = m_fstypes.find(std::string(fsname));
        if (it == std::end(m_fstypes)) {
            LOG_ERROR("VFS: filesystem %.*s doesn't exists in manager.", int(fsname.length()), fsname.data());
            LOG_ERROR("VFS: filesystem %s doesn't exists in manager.", std::string(fsname).c_str());
            return -ENOENT;
        }
        if (it->second->mount_count() > 0) {


@@ 74,7 74,7 @@ namespace purefs::fs
    {
        // Sanity check input data
        if (target.size() <= 1 || target[0] != '/') {
            LOG_ERROR("VFS: Invalid target mountpoint path %.*s", int(target.length()), target.data());
            LOG_ERROR("VFS: Invalid target mountpoint path %s", std::string(target).c_str());
            return -EINVAL;
        }
        if (flags & ~(mount_flags::remount | mount_flags::read_only)) {

M module-vfs/src/purefs/vfs_subsystem.cpp => module-vfs/src/purefs/vfs_subsystem.cpp +29 -9
@@ 25,6 25,7 @@ namespace purefs::subsystem
        constexpr auto new_layout_part_count = 3;
        constexpr auto boot_size_limit       = 16384L;
        constexpr auto block_size_max_shift  = 21;
        constexpr auto block_size_min_shift  = 8;
        namespace json
        {
            constexpr auto os_type = "ostype";


@@ 90,6 91,27 @@ namespace purefs::subsystem
            }
            return json[json::main][json::os_type].string_value();
        }

        int read_mbr_lfs_erase_size(std::shared_ptr<blkdev::disk_manager> disk_mngr,
                                    std::string_view dev_name,
                                    int part_no)
        {
            static constexpr auto MBR_ERASE_BLK_OFFSET = 0x00E0;
            if (part_no <= 0) {
                return -EINVAL;
            }
            const auto sect_size = disk_mngr->get_info(dev_name, blkdev::info_type::sector_size);
            if (sect_size <= MBR_ERASE_BLK_OFFSET + part_no) {
                return (sect_size > 0) ? (-ERANGE) : (sect_size);
            }
            auto mbr_buf = std::make_unique<char[]>(sect_size);
            int err      = disk_mngr->read(dev_name, mbr_buf.get(), 0, 1);
            if (err < 0) {
                return err;
            }
            return mbr_buf[MBR_ERASE_BLK_OFFSET + part_no];
        }

    } // namespace

    auto initialize() -> std::tuple<std::shared_ptr<blkdev::disk_manager>, std::shared_ptr<fs::filesystem>>


@@ 172,16 194,14 @@ namespace purefs::subsystem
            return err;
        }
        if (lfs_it != std::end(parts)) {
            if (lfs_it->boot_unit > block_size_max_shift) {
                LOG_FATAL("Boot sector size is out of range");
                return -ERANGE;
            }
            else {
                const uint32_t lfs_block_size = 1U << lfs_it->boot_unit;
                const auto lfs_block_size_ptr = (lfs_it->boot_unit) ? (&lfs_block_size) : nullptr;
                err                           = vfs->mount(
                    lfs_it->name, purefs::dir::getUserDiskPath().string(), "littlefs", 0, lfs_block_size_ptr);
            int lfs_block_log2           = read_mbr_lfs_erase_size(disk, default_blkdev_name, lfs_it->physical_number);
            uint32_t lfs_block_size      = 0;
            uint32_t *lfs_block_size_ptr = nullptr;
            if (lfs_block_log2 >= block_size_min_shift && lfs_block_log2 <= block_size_max_shift) {
                lfs_block_size     = 1U << lfs_block_log2;
                lfs_block_size_ptr = &lfs_block_size;
            }
            err = vfs->mount(lfs_it->name, purefs::dir::getUserDiskPath().string(), "littlefs", 0, lfs_block_size_ptr);
        }
        const std::string json_file = (dir::getRootDiskPath() / file::boot_json).string();
        const auto boot_dir_name    = parse_boot_json_directory(json_file);