From 436c2ed3cc1defc2d415b2b918da6b1d4d861abb Mon Sep 17 00:00:00 2001 From: Lucjan Bryndza Date: Wed, 3 Feb 2021 15:47:39 +0100 Subject: [PATCH] [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 --- host-tools/genlittlefs/lfs_ioaccess.c | 4 ++ host-tools/genlittlefs/mklfs.c | 5 +- host-tools/genlittlefs/parse_partitions.c | 66 +++++++++++++------ module-vfs/src/newlib/vfs_io_syscalls.cpp | 8 ++- .../src/purefs/blkdev/partition_parser.cpp | 14 ++-- module-vfs/src/purefs/fs/filesystem.cpp | 4 +- module-vfs/src/purefs/vfs_subsystem.cpp | 38 ++++++++--- 7 files changed, 98 insertions(+), 41 deletions(-) diff --git a/host-tools/genlittlefs/lfs_ioaccess.c b/host-tools/genlittlefs/lfs_ioaccess.c index 5fcd2e7601ccf9f95e0ae7a01aa73699563dfbea..4bbad0568cd149582482ec1e913b7f8e083c7e43 100644 --- a/host-tools/genlittlefs/lfs_ioaccess.c +++ b/host-tools/genlittlefs/lfs_ioaccess.c @@ -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; diff --git a/host-tools/genlittlefs/mklfs.c b/host-tools/genlittlefs/mklfs.c index ab81c3dceab40b0be6cf94e2341b536ecce6bc23..e34b943577d09add7b223a21f40f21a316055d82 100644 --- a/host-tools/genlittlefs/mklfs.c +++ b/host-tools/genlittlefs/mklfs.c @@ -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; } diff --git a/host-tools/genlittlefs/parse_partitions.c b/host-tools/genlittlefs/parse_partitions.c index 5aafd04675311907011149dfd409b38953f955b4..4c72a1a94da8353f56afda93609a2413eec99213 100644 --- a/host-tools/genlittlefs/parse_partitions.c +++ b/host-tools/genlittlefs/parse_partitions.c @@ -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 #include "parse_partitions.h" @@ -6,10 +6,14 @@ #include #include #include - +#include +#include +#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; +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); } diff --git a/module-vfs/src/newlib/vfs_io_syscalls.cpp b/module-vfs/src/newlib/vfs_io_syscalls.cpp index 2366baea0d258f34449718fdc56017bb577d1273..e3461c43717d8ef1f2d8e5d188a8198ee4261021 100644 --- a/module-vfs/src/newlib/vfs_io_syscalls.cpp +++ b/module-vfs/src/newlib/vfs_io_syscalls.cpp @@ -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 diff --git a/module-vfs/src/purefs/blkdev/partition_parser.cpp b/module-vfs/src/purefs/blkdev/partition_parser.cpp index 4a75aca51f68bb56bd2619223c7ab9bce099b67e..01524dd0ec14997b7bab05dd8050c48a1f4fcfc5 100644 --- a/module-vfs/src/purefs/blkdev/partition_parser.cpp +++ b/module-vfs/src/purefs/blkdev/partition_parser.cpp @@ -94,13 +94,13 @@ namespace purefs::blkdev::internal auto partition_parser::check_partition(const std::shared_ptr 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(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), diff --git a/module-vfs/src/purefs/fs/filesystem.cpp b/module-vfs/src/purefs/fs/filesystem.cpp index 0398e12019799677ab67bb80e5d580dd6bc3096b..c079457ae57c5391f5e3f23d0032737b804202be 100644 --- a/module-vfs/src/purefs/fs/filesystem.cpp +++ b/module-vfs/src/purefs/fs/filesystem.cpp @@ -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)) { diff --git a/module-vfs/src/purefs/vfs_subsystem.cpp b/module-vfs/src/purefs/vfs_subsystem.cpp index 967435fb758644081b234dcef2b5c852e6b9385b..3c3ee90678bf44026af7b389ca2b19d33122968c 100644 --- a/module-vfs/src/purefs/vfs_subsystem.cpp +++ b/module-vfs/src/purefs/vfs_subsystem.cpp @@ -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 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(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> @@ -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);