From af960b6fac2fdd9e42072c4632ca769fce76f95f Mon Sep 17 00:00:00 2001 From: Lucjan Bryndza Date: Thu, 21 Jan 2021 16:15:58 +0100 Subject: [PATCH] [EGD-5146] Add read LFS block size from part Add littlefs block size from partition bootable offset --- .../libiosyscalls/src/syscalls_posix.cpp | 2 +- host-tools/genlittlefs/mklfs.c | 6 +++ host-tools/genlittlefs/parse_partitions.c | 51 +++++++++++++++++++ host-tools/genlittlefs/parse_partitions.h | 4 ++ .../purefs/fs/drivers/filesystem_littlefs.hpp | 2 +- .../purefs/fs/drivers/filesystem_vfat.hpp | 2 +- .../src/purefs/fs/filesystem_littlefs.cpp | 26 +++++++--- .../drivers/src/purefs/fs/filesystem_vfat.cpp | 4 +- .../purefs/fs/filesystem_operations.hpp | 8 +-- .../include/user/purefs/blkdev/partition.hpp | 1 + .../include/user/purefs/fs/filesystem.hpp | 9 +++- module-vfs/src/newlib/vfs_io_syscalls.cpp | 4 +- .../src/purefs/blkdev/partition_parser.cpp | 1 + module-vfs/src/purefs/fs/filesystem.cpp | 5 +- .../src/purefs/fs/filesystem_operations.cpp | 2 +- module-vfs/src/purefs/vfs_subsystem.cpp | 17 +++++-- 16 files changed, 117 insertions(+), 27 deletions(-) rename module-vfs/include/{user => internal}/purefs/fs/filesystem_operations.hpp (94%) diff --git a/board/linux/libiosyscalls/src/syscalls_posix.cpp b/board/linux/libiosyscalls/src/syscalls_posix.cpp index 0a78fa27110ffd57f59ccdbb337ce65d2145ecb5..893ccbf0b47cbfe74a16c5fc5f51e0f6fa6e6e0e 100644 --- a/board/linux/libiosyscalls/src/syscalls_posix.cpp +++ b/board/linux/libiosyscalls/src/syscalls_posix.cpp @@ -626,7 +626,7 @@ extern "C" { if (vfs::redirect_to_image(dir)) { TRACE_SYSCALLN("(%s, %s, %s, %08lx, %p) -> VFS", special_file, dir, fstype, rwflag, data); - return vfs::invoke_fs(&fs::mount, special_file, dir, fstype, rwflag); + return vfs::invoke_fs(&fs::mount, special_file, dir, fstype, rwflag, data); } else { TRACE_SYSCALLN("(%s, %s, %s, %08lx,%p) -> linux fs", special_file, dir, fstype, rwflag, data); diff --git a/host-tools/genlittlefs/mklfs.c b/host-tools/genlittlefs/mklfs.c index 2a5a97572a15634a8e83090eae92b96205dd001e..ab81c3dceab40b0be6cf94e2341b536ecce6bc23 100644 --- a/host-tools/genlittlefs/mklfs.c +++ b/host-tools/genlittlefs/mklfs.c @@ -291,6 +291,12 @@ int main(int argc, char **argv) return EXIT_FAILURE; } free(parts); + if (write_partition_bootunit(lopts.dst_image, lopts.partition_num, lopts.block_size)) { + perror("Unable to write bootunit"); + free(lopts.src_dirs); + lfs_ioaccess_close(ioctx); + return EXIT_FAILURE; + } } else if (lopts.mode == littlefs_opts_file) { int fds = open(lopts.dst_image, O_CREAT | O_WRONLY, 0644); diff --git a/host-tools/genlittlefs/parse_partitions.c b/host-tools/genlittlefs/parse_partitions.c index e59dfdfb11b4f15ae52b90c45180522638b586ce..5aafd04675311907011149dfd409b38953f955b4 100644 --- a/host-tools/genlittlefs/parse_partitions.c +++ b/host-tools/genlittlefs/parse_partitions.c @@ -5,8 +5,11 @@ #include #include #include +#include static const size_t sector_size = 512; +static const size_t part_offset = 446; +static const size_t part_size = 16; struct partition *find_partitions(const char *filename, part_type_t ptype, size_t *nelems) { @@ -61,3 +64,51 @@ void print_partitions(const struct partition *part, size_t nparts) part[s].end / 1024); } } + +static inline unsigned calculate_shift(uint32_t v) +{ + + static const int mult_bruijn_bit_position[32] = {0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31}; + + v |= v >> 1; // first round down to one less than a power of 2 + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + + return mult_bruijn_bit_position[(uint32_t)(v * 0x07C4ACDDU) >> 27]; +} + +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); + return -1; + } + uint8_t boot_rd; + if (fread(&boot_rd, sizeof boot_rd, 1, fil) != 1) { + fclose(fil); + return -1; + } + if (fseek(fil, fil_offs, SEEK_SET) < 0) { + fclose(fil); + return -1; + } + uint8_t boot_wr = (boot_rd & 0x80) | (boot & 0x7f); + if (fwrite(&boot_wr, sizeof boot_wr, 1, fil) != 1) { + fclose(fil); + return -1; + } + return fclose(fil); +} diff --git a/host-tools/genlittlefs/parse_partitions.h b/host-tools/genlittlefs/parse_partitions.h index ec098021abb17c4465fa8778b9444ebf6c73581c..b77f0f29e11084e5c89dc3b5d061461c3f8c66ee 100644 --- a/host-tools/genlittlefs/parse_partitions.h +++ b/host-tools/genlittlefs/parse_partitions.h @@ -3,6 +3,8 @@ #pragma once #include +#include +#include typedef int part_type_t; @@ -22,3 +24,5 @@ struct partition *find_partitions(const char *filename, part_type_t ptype, size_ __attribute__((nonnull(1, 3))); void print_partitions(const struct partition *part, size_t nparts); + +int write_partition_bootunit(const char *filename, int part_num, uint32_t block_size); diff --git a/module-vfs/drivers/include/purefs/fs/drivers/filesystem_littlefs.hpp b/module-vfs/drivers/include/purefs/fs/drivers/filesystem_littlefs.hpp index e388f806810f157602f6bbca97548f93ee116df9..1ec3aef39fd9f6842f1680fc5ce6b9ecd75817c2 100644 --- a/module-vfs/drivers/include/purefs/fs/drivers/filesystem_littlefs.hpp +++ b/module-vfs/drivers/include/purefs/fs/drivers/filesystem_littlefs.hpp @@ -22,7 +22,7 @@ namespace purefs::fs::drivers */ auto mount_prealloc(std::shared_ptr diskh, std::string_view path, unsigned flags) -> fsmount override; - auto mount(fsmount mnt) noexcept -> int override; + auto mount(fsmount mnt, const void *data) 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; diff --git a/module-vfs/drivers/include/purefs/fs/drivers/filesystem_vfat.hpp b/module-vfs/drivers/include/purefs/fs/drivers/filesystem_vfat.hpp index d8c1be2c9ef3218a58c32cb21d613592bdda90a0..e3a4e5cdff80103dd653848e5f72360de66e1061 100644 --- a/module-vfs/drivers/include/purefs/fs/drivers/filesystem_vfat.hpp +++ b/module-vfs/drivers/include/purefs/fs/drivers/filesystem_vfat.hpp @@ -16,7 +16,7 @@ namespace purefs::fs::drivers private: auto mount_prealloc(std::shared_ptr diskh, std::string_view path, unsigned flags) -> fsmount override; - auto mount(fsmount mnt) noexcept -> int override; + auto mount(fsmount mnt, const void *data) 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; diff --git a/module-vfs/drivers/src/purefs/fs/filesystem_littlefs.cpp b/module-vfs/drivers/src/purefs/fs/filesystem_littlefs.cpp index f7f48c40f28f8e85f4a99ba71a4ec2823c920f7b..007cdb8036dd3a7645839efe0d35b1c3543e2c74 100644 --- a/module-vfs/drivers/src/purefs/fs/filesystem_littlefs.cpp +++ b/module-vfs/drivers/src/purefs/fs/filesystem_littlefs.cpp @@ -112,11 +112,21 @@ namespace st.st_mode = translate_attrib_to_st_mode(fs.type, readOnly); } - [[gnu::nonnull(1)]] int setup_lfs_config(lfs_config *cfg, size_t sector_size, size_t part_sectors_count) + [[gnu::nonnull(1)]] int setup_lfs_config(lfs_config *cfg, + size_t sector_size, + size_t part_sectors_count, + const void *data) { - cfg->block_cycles = 512; - cfg->block_size = c_lfs_block_size; - cfg->block_count = 0; // Read later from super block + if (data) { + // NOTE: block size from mount param + cfg->block_size = *(reinterpret_cast(data)); + } + else { + cfg->block_size = c_lfs_block_size; + LOG_WARN("LFS: mount block size not specified using default value"); + } + cfg->block_cycles = 512; + cfg->block_count = 0; // Read later from super block cfg->lookahead_size = 131072; const auto total_siz = uint64_t(sector_size) * uint64_t(part_sectors_count); if (total_siz % cfg->block_size) { @@ -127,7 +137,7 @@ namespace cfg->read_size = cfg->block_size; cfg->prog_size = cfg->block_size; cfg->cache_size = cfg->block_size; - LOG_INFO("LFS: block_count %u sector_size %u", unsigned(cfg->block_count), unsigned(cfg->block_size)); + LOG_INFO("LFS: block count %u block size %u", unsigned(cfg->block_count), unsigned(cfg->block_size)); return 0; } @@ -207,7 +217,7 @@ namespace purefs::fs::drivers return std::make_shared(diskh, path, flags, shared_from_this()); } - auto filesystem_littlefs::mount(fsmount mnt) noexcept -> int + auto filesystem_littlefs::mount(fsmount mnt, const void *data) noexcept -> int { auto disk = mnt->disk(); if (!disk) { @@ -232,7 +242,7 @@ namespace purefs::fs::drivers else { auto sect_count = diskmm->get_info(disk, blkdev::info_type::sector_count); if (sect_count > 0) { - err = setup_lfs_config(vmnt->lfs_config(), ssize, sect_count); + err = setup_lfs_config(vmnt->lfs_config(), ssize, sect_count, data); } else { LOG_ERROR("Unable to read sector count %i", int(sect_count)); @@ -247,7 +257,7 @@ namespace purefs::fs::drivers LOG_ERROR("LFS mount error %i", err); } if (!err) { - filesystem_operations::mount(mnt); + filesystem_operations::mount(mnt, data); } else { littlefs::internal::remove_volume(vmnt->lfs_config()); diff --git a/module-vfs/drivers/src/purefs/fs/filesystem_vfat.cpp b/module-vfs/drivers/src/purefs/fs/filesystem_vfat.cpp index f66663ae9c439db62fc54595be50cede075d2d62..e76885fb314a9c0f0598eb048f2476c2ff5122e9 100644 --- a/module-vfs/drivers/src/purefs/fs/filesystem_vfat.cpp +++ b/module-vfs/drivers/src/purefs/fs/filesystem_vfat.cpp @@ -148,7 +148,7 @@ namespace purefs::fs::drivers return std::make_shared(diskh, path, flags, shared_from_this()); } - auto filesystem_vfat::mount(fsmount mnt) noexcept -> int + auto filesystem_vfat::mount(fsmount mnt, const void *data) noexcept -> int { auto disk = mnt->disk(); if (!disk) { @@ -168,7 +168,7 @@ namespace purefs::fs::drivers ret = f_mount(vmnt->fatfs(), vmnt->ff_drive(), 1); ret = translate_error(ret); if (!ret) { - filesystem_operations::mount(mnt); + filesystem_operations::mount(mnt, data); } return ret; } diff --git a/module-vfs/include/user/purefs/fs/filesystem_operations.hpp b/module-vfs/include/internal/purefs/fs/filesystem_operations.hpp similarity index 94% rename from module-vfs/include/user/purefs/fs/filesystem_operations.hpp rename to module-vfs/include/internal/purefs/fs/filesystem_operations.hpp index fdea505144e39c2f903213c127e293aabba03668..d53f6965982dba9f9eea2a2adeea911f331a75da 100644 --- a/module-vfs/include/user/purefs/fs/filesystem_operations.hpp +++ b/module-vfs/include/internal/purefs/fs/filesystem_operations.hpp @@ -17,7 +17,7 @@ namespace purefs::blkdev class disk_handle; } class disk_manager; -} +} // namespace purefs::blkdev namespace purefs::fs { @@ -44,9 +44,9 @@ namespace purefs::fs */ virtual auto mount_prealloc(std::shared_ptr diskh, std::string_view path, - unsigned flags) -> fsmount = 0; - virtual auto mount(fsmount mnt) noexcept -> int = 0; - virtual auto umount(fsmount mnt) noexcept -> int = 0; + unsigned flags) -> fsmount = 0; + virtual auto mount(fsmount mnt, const void *data) noexcept -> int = 0; + virtual auto umount(fsmount mnt) noexcept -> int = 0; virtual auto stat_vfs(fsmount mnt, std::string_view path, statvfs &stat) const noexcept -> int; /** Standard file access API */ diff --git a/module-vfs/include/user/purefs/blkdev/partition.hpp b/module-vfs/include/user/purefs/blkdev/partition.hpp index c9167cc4d7686bf118a1cc5ea5db3f7283dcba31..e459400c1880c67a78e8eea103f820a0f99c1951 100644 --- a/module-vfs/include/user/purefs/blkdev/partition.hpp +++ b/module-vfs/include/user/purefs/blkdev/partition.hpp @@ -16,6 +16,7 @@ namespace purefs::blkdev sector_t start_sector{}; //! First sector std::size_t num_sectors{}; //! Number of sectors bool bootable{}; //! Partition is bootable + unsigned char boot_unit{}; //! 7 bit boot unit field unsigned short type{}; //! Partition code std::string name; //! Partition name in block manager }; diff --git a/module-vfs/include/user/purefs/fs/filesystem.hpp b/module-vfs/include/user/purefs/fs/filesystem.hpp index 347f6340382231e7b591f00aaabb6de95b3a3e2b..7231b06ca0a8464a19b10d8b476e9101740a0b5a 100644 --- a/module-vfs/include/user/purefs/fs/filesystem.hpp +++ b/module-vfs/include/user/purefs/fs/filesystem.hpp @@ -80,13 +80,18 @@ namespace purefs::fs auto unregister_filesystem(std::string_view fsname) -> int; /** Mount filesystem to the the specified mount point + * see man(2) mount * @param[in] dev_or_part Device or partition for mount * @param[in] target Target path where the fs will be mounted * @param[in] flags Mount flags + * @param[in] data Filesystem specific configuration * @return zero on success otherwise error */ - auto mount(std::string_view dev_or_part, std::string_view target, std::string_view fs_type, unsigned flags = 0) - -> int; + auto mount(std::string_view dev_or_part, + std::string_view target, + std::string_view fs_type, + unsigned flags = 0, + const void *data = nullptr) -> int; /** Unmont filesystem from selected mount point * @param[in] mount_point Mount point where the fs is mounted * @return zero on success otherwise error diff --git a/module-vfs/src/newlib/vfs_io_syscalls.cpp b/module-vfs/src/newlib/vfs_io_syscalls.cpp index d5dc62620c59749032e9946bfe31e4229a84e082..2366baea0d258f34449718fdc56017bb577d1273 100644 --- a/module-vfs/src/newlib/vfs_io_syscalls.cpp +++ b/module-vfs/src/newlib/vfs_io_syscalls.cpp @@ -353,9 +353,9 @@ namespace vfsn::internal::syscalls const char *dir, const char *fstype, unsigned long int rwflag, - const void * /*data*/) + const void *data) { - return invoke_fs(_errno_, &purefs::fs::filesystem::mount, special_file, dir, fstype, rwflag); + return invoke_fs(_errno_, &purefs::fs::filesystem::mount, special_file, dir, fstype, rwflag, data); } } // namespace vfsn::internal::syscalls diff --git a/module-vfs/src/purefs/blkdev/partition_parser.cpp b/module-vfs/src/purefs/blkdev/partition_parser.cpp index 3b3707d6ce638550bca64f191ee8bc3f12c274d7..c2d0022f6ac0b54c62e7fd61d3a2587fbd47d208 100644 --- a/module-vfs/src/purefs/blkdev/partition_parser.cpp +++ b/module-vfs/src/purefs/blkdev/partition_parser.cpp @@ -94,6 +94,7 @@ namespace purefs::blkdev::internal std::size_t offs = defs::ptbl_offs; for (auto &part : parts) { part.bootable = buffer[defs::mbr_ptbl_active + offs] & 0x80; + part.boot_unit = buffer[defs::mbr_ptbl_active + offs] & 0x7F; part.type = buffer[defs::mbr_ptbl_type + offs]; part.num_sectors = to_word(buffer, defs::mbr_ptbl_sect_cnt + offs); part.start_sector = to_word(buffer, defs::mbr_ptbl_lba + offs); diff --git a/module-vfs/src/purefs/fs/filesystem.cpp b/module-vfs/src/purefs/fs/filesystem.cpp index a3fa3f45f4a6d7d8b481b6b5d05e511bc0ea4ea5..0398e12019799677ab67bb80e5d580dd6bc3096b 100644 --- a/module-vfs/src/purefs/fs/filesystem.cpp +++ b/module-vfs/src/purefs/fs/filesystem.cpp @@ -69,7 +69,8 @@ namespace purefs::fs auto filesystem::mount(std::string_view dev_or_part, std::string_view target, std::string_view fs_type, - unsigned flags) -> int + unsigned flags, + const void *data) -> int { // Sanity check input data if (target.size() <= 1 || target[0] != '/') { @@ -128,7 +129,7 @@ namespace purefs::fs } if (diskh) { const auto mnt_point = vsi->second->mount_prealloc(diskh, target, flags); - const auto ret_mnt = vsi->second->mount(mnt_point); + const auto ret_mnt = vsi->second->mount(mnt_point, data); if (!ret_mnt) { m_mounts.emplace(std::make_pair(target, mnt_point)); m_partitions.emplace(dev_or_part); diff --git a/module-vfs/src/purefs/fs/filesystem_operations.cpp b/module-vfs/src/purefs/fs/filesystem_operations.cpp index 685b75a668c7a0aa0bffc06cadb8349193afc9f2..ebf7320ca7ea39393665019775287206766cadae 100644 --- a/module-vfs/src/purefs/fs/filesystem_operations.cpp +++ b/module-vfs/src/purefs/fs/filesystem_operations.cpp @@ -8,7 +8,7 @@ namespace purefs::fs { - auto filesystem_operations::mount(fsmount mnt) noexcept -> int + auto filesystem_operations::mount(fsmount mnt, const void *data) noexcept -> int { ++m_mount_count; return -ENOTSUP; diff --git a/module-vfs/src/purefs/vfs_subsystem.cpp b/module-vfs/src/purefs/vfs_subsystem.cpp index ed81ac24cb5293059ef8570502496fe6682ee1d1..6f328043b694265eee3672f9d0b95cf935795814 100644 --- a/module-vfs/src/purefs/vfs_subsystem.cpp +++ b/module-vfs/src/purefs/vfs_subsystem.cpp @@ -24,6 +24,7 @@ namespace purefs::subsystem constexpr auto old_layout_part_count = 2; constexpr auto new_layout_part_count = 3; constexpr auto boot_size_limit = 16384L; + constexpr auto block_size_max_shift = 21; namespace json { constexpr auto os_type = "ostype"; @@ -150,8 +151,9 @@ namespace purefs::subsystem } } 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."); + LOG_ERROR("!!!! Caution !!!! eMMC is formated with vFAT old layout scheme. Filesystem may be currupted on " + "power loss."); + LOG_WARN("Please upgrade to new partition scheme based on the LittleFS filesystem."); } if (boot_it == std::end(parts)) { LOG_FATAL("Unable to find boot partition"); @@ -167,7 +169,16 @@ namespace purefs::subsystem return err; } if (lfs_it != std::end(parts)) { - err = vfs->mount(lfs_it->name, purefs::dir::getUserDiskPath().string(), "littlefs"); + 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); + } } const std::string json_file = (dir::getRootDiskPath() / file::boot_json).string(); const auto boot_dir_name = parse_boot_json_directory(json_file);