From 20b669a23d50bf191dc7225527487f9148122b8c Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 8 Aug 2018 09:37:43 -0500 Subject: [PATCH] Fixed issue with big-endian CTZ lists intertwined in commit logic Found while testing big-endian support. Basically, if littlefs is really really unlucky, the block allocator could kick in while committing a file's CTZ reference. If this happens, the block allocator will need to traverse all CTZ skip-lists in memory, including the skip-list we're committing. This means we can't convert the CTZ's endianness in place, and need to make a copy on big-endian systems. We rely on dead-code elimination from the compiler to make the conditional behaviour for big-endian vs little-endian system a noop determined by the lfs_tole32 intrinsic. --- lfs.c | 12 +++++++----- lfs_util.h | 22 +++++++++++----------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/lfs.c b/lfs.c index a950c4a2860..faa5bbe6d30 100644 --- a/lfs.c +++ b/lfs.c @@ -2199,25 +2199,27 @@ int lfs_file_sync(lfs_t *lfs, lfs_file_t *file) { uint16_t type; const void *buffer; lfs_size_t size; + struct lfs_ctz ctz; if (file->flags & LFS_F_INLINE) { // inline the whole file type = LFS_TYPE_INLINESTRUCT; buffer = file->cache.buffer; size = file->ctz.size; - } else { + } else if (lfs_tole32(0x11223344) == 0x11223344) { // update the ctz reference type = LFS_TYPE_CTZSTRUCT; - buffer = &file->ctz; - size = sizeof(file->ctz); + // copy ctz so alloc will work during a relocate + ctz = file->ctz; + lfs_ctz_tole32(&ctz); + buffer = &ctz; + size = sizeof(ctz); } // commit file data and attributes - lfs_ctz_tole32(&file->ctz); err = lfs_dir_commit(lfs, &file->m, LFS_MKATTR(type, file->id, buffer, size, LFS_MKATTR(LFS_FROM_ATTRS, file->id, file->cfg->attrs, 0, NULL))); - lfs_ctz_fromle32(&file->ctz); if (err) { if (err == LFS_ERR_NOSPC && (file->flags & LFS_F_INLINE)) { goto relocate; diff --git a/lfs_util.h b/lfs_util.h index 80b4002b2aa..8a65694c1f5 100644 --- a/lfs_util.h +++ b/lfs_util.h @@ -11,8 +11,8 @@ // LFS_CONFIG as a header file to include (-DLFS_CONFIG=lfs_config.h). // // If LFS_CONFIG is used, none of the default utils will be emitted and must be -// provided by the config file. To start I would suggest copying lfs_util.h and -// modifying as needed. +// provided by the config file. To start, I would suggest copying lfs_util.h +// and modifying as needed. #ifdef LFS_CONFIG #define LFS_STRINGIZE(x) LFS_STRINGIZE2(x) #define LFS_STRINGIZE2(x) #x @@ -88,6 +88,15 @@ static inline uint32_t lfs_min(uint32_t a, uint32_t b) { return (a < b) ? a : b; } +// Align to nearest multiple of a size +static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { + return a - (a % alignment); +} + +static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { + return lfs_aligndown(a + alignment-1, alignment); +} + // Find the next smallest power of 2 less than or equal to a static inline uint32_t lfs_npw2(uint32_t a) { #if !defined(LFS_NO_INTRINSICS) && (defined(__GNUC__) || defined(__CC_ARM)) @@ -177,15 +186,6 @@ static inline uint16_t lfs_tole16(uint16_t a) { return lfs_fromle16(a); } -// Align to nearest multiple of a size -static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { - return a - (a % alignment); -} - -static inline uint32_t lfs_alignup(uint32_t a, uint32_t alignment) { - return lfs_aligndown(a + alignment-1, alignment); -} - // Calculate CRC-32 with polynomial = 0x04c11db7 uint32_t lfs_crc(uint32_t crc, const void *buffer, size_t size);