Ver Fonte

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.
Christopher Haster há 7 anos atrás
pai
commit
20b669a23d
2 ficheiros alterados com 18 adições e 16 exclusões
  1. 7 5
      lfs.c
  2. 11 11
      lfs_util.h

+ 7 - 5
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;

+ 11 - 11
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);