Quellcode durchsuchen

Manual update to LFS 2.4, see https://github.com/littlefs-project/littlefs

lorol vor 4 Jahren
Ursprung
Commit
fe1369cc50
3 geänderte Dateien mit 102 neuen und 46 gelöschten Zeilen
  1. 84 44
      src/lfs.c
  2. 8 2
      src/lfs.h
  3. 10 0
      src/lfs_util.h

+ 84 - 44
src/lfs.c

@@ -430,7 +430,8 @@ static inline void lfs_superblock_tole32(lfs_superblock_t *superblock) {
     superblock->attr_max    = lfs_tole32(superblock->attr_max);
 }
 
-static inline bool lfs_mlist_isopen(struct lfs_mlist *head,
+#ifndef LFS_NO_ASSERT
+static bool lfs_mlist_isopen(struct lfs_mlist *head,
         struct lfs_mlist *node) {
     for (struct lfs_mlist **p = &head; *p; p = &(*p)->next) {
         if (*p == (struct lfs_mlist*)node) {
@@ -440,8 +441,9 @@ static inline bool lfs_mlist_isopen(struct lfs_mlist *head,
 
     return false;
 }
+#endif
 
-static inline void lfs_mlist_remove(lfs_t *lfs, struct lfs_mlist *mlist) {
+static void lfs_mlist_remove(lfs_t *lfs, struct lfs_mlist *mlist) {
     for (struct lfs_mlist **p = &lfs->mlist; *p; p = &(*p)->next) {
         if (*p == mlist) {
             *p = (*p)->next;
@@ -450,7 +452,7 @@ static inline void lfs_mlist_remove(lfs_t *lfs, struct lfs_mlist *mlist) {
     }
 }
 
-static inline void lfs_mlist_append(lfs_t *lfs, struct lfs_mlist *mlist) {
+static void lfs_mlist_append(lfs_t *lfs, struct lfs_mlist *mlist) {
     mlist->next = lfs->mlist;
     lfs->mlist = mlist;
 }
@@ -470,7 +472,7 @@ static int lfs_file_rawsync(lfs_t *lfs, lfs_file_t *file);
 static int lfs_file_outline(lfs_t *lfs, lfs_file_t *file);
 static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file);
 
-static void lfs_fs_preporphans(lfs_t *lfs, int8_t orphans);
+static int lfs_fs_preporphans(lfs_t *lfs, int8_t orphans);
 static void lfs_fs_prepmove(lfs_t *lfs,
         uint16_t id, const lfs_block_t pair[2]);
 static int lfs_fs_pred(lfs_t *lfs, const lfs_block_t dir[2],
@@ -1594,7 +1596,8 @@ static int lfs_dir_compact(lfs_t *lfs,
         // for metadata updates.
         if (end - begin < 0xff &&
                 size <= lfs_min(lfs->cfg->block_size - 36,
-                    lfs_alignup(lfs->cfg->block_size/2,
+                    lfs_alignup((lfs->cfg->metadata_max ?
+                            lfs->cfg->metadata_max : lfs->cfg->block_size)/2,
                         lfs->cfg->prog_size))) {
             break;
         }
@@ -1679,7 +1682,8 @@ static int lfs_dir_compact(lfs_t *lfs,
                 .crc = 0xffffffff,
 
                 .begin = 0,
-                .end = lfs->cfg->block_size - 8,
+                .end = (lfs->cfg->metadata_max ?
+                    lfs->cfg->metadata_max : lfs->cfg->block_size) - 8,
             };
 
             // erase block to write to
@@ -1889,7 +1893,8 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
             .crc = 0xffffffff,
 
             .begin = dir->off,
-            .end = lfs->cfg->block_size - 8,
+            .end = (lfs->cfg->metadata_max ?
+                lfs->cfg->metadata_max : lfs->cfg->block_size) - 8,
         };
 
         // traverse attrs that need to be written out
@@ -2066,7 +2071,10 @@ static int lfs_rawmkdir(lfs_t *lfs, const char *path) {
     // current block end of list?
     if (cwd.m.split) {
         // update tails, this creates a desync
-        lfs_fs_preporphans(lfs, +1);
+        err = lfs_fs_preporphans(lfs, +1);
+        if (err) {
+            return err;
+        }
 
         // it's possible our predecessor has to be relocated, and if
         // our parent is our predecessor's predecessor, this could have
@@ -2086,7 +2094,10 @@ static int lfs_rawmkdir(lfs_t *lfs, const char *path) {
         }
 
         lfs->mlist = cwd.next;
-        lfs_fs_preporphans(lfs, -1);
+        err = lfs_fs_preporphans(lfs, -1);
+        if (err) {
+            return err;
+        }
     }
 
     // now insert into our parent block
@@ -2971,7 +2982,9 @@ static lfs_ssize_t lfs_file_rawwrite(lfs_t *lfs, lfs_file_t *file,
     if ((file->flags & LFS_F_INLINE) &&
             lfs_max(file->pos+nsize, file->ctz.size) >
             lfs_min(0x3fe, lfs_min(
-                lfs->cfg->cache_size, lfs->cfg->block_size/8))) {
+                lfs->cfg->cache_size,
+                (lfs->cfg->metadata_max ?
+                    lfs->cfg->metadata_max : lfs->cfg->block_size) / 8))) {
         // inline file doesn't fit anymore
         int err = lfs_file_outline(lfs, file);
         if (err) {
@@ -3053,14 +3066,6 @@ relocate:
 
 static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file,
         lfs_soff_t off, int whence) {
-#ifndef LFS_READONLY
-    // write out everything beforehand, may be noop if rdonly
-    int err = lfs_file_flush(lfs, file);
-    if (err) {
-        return err;
-    }
-#endif
-
     // find new pos
     lfs_off_t npos = file->pos;
     if (whence == LFS_SEEK_SET) {
@@ -3068,7 +3073,7 @@ static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file,
     } else if (whence == LFS_SEEK_CUR) {
         npos = file->pos + off;
     } else if (whence == LFS_SEEK_END) {
-        npos = file->ctz.size + off;
+        npos = lfs_file_rawsize(lfs, file) + off;
     }
 
     if (npos > lfs->file_max) {
@@ -3076,6 +3081,19 @@ static lfs_soff_t lfs_file_rawseek(lfs_t *lfs, lfs_file_t *file,
         return LFS_ERR_INVAL;
     }
 
+    if (file->pos == npos) {
+        // noop - position has not changed
+        return npos;
+    }
+
+#ifndef LFS_READONLY
+    // write out everything beforehand, may be noop if rdonly
+    int err = lfs_file_flush(lfs, file);
+    if (err) {
+        return err;
+    }
+#endif
+
     // update pos
     file->pos = npos;
     return npos;
@@ -3106,21 +3124,22 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
             return err;
         }
 
+        // need to set pos/block/off consistently so seeking back to
+        // the old position does not get confused
+        file->pos = size;
         file->ctz.head = file->block;
         file->ctz.size = size;
         file->flags |= LFS_F_DIRTY | LFS_F_READING;
     } else if (size > oldsize) {
         // flush+seek if not already at end
-        if (file->pos != oldsize) {
-            lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_END);
-            if (res < 0) {
-                return (int)res;
-            }
+        lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_END);
+        if (res < 0) {
+            return (int)res;
         }
 
         // fill with zeros
         while (file->pos < size) {
-            lfs_ssize_t res = lfs_file_rawwrite(lfs, file, &(uint8_t){0}, 1);
+            res = lfs_file_rawwrite(lfs, file, &(uint8_t){0}, 1);
             if (res < 0) {
                 return (int)res;
             }
@@ -3211,7 +3230,10 @@ static int lfs_rawremove(lfs_t *lfs, const char *path) {
         }
 
         // mark fs as orphaned
-        lfs_fs_preporphans(lfs, +1);
+        err = lfs_fs_preporphans(lfs, +1);
+        if (err) {
+            return err;
+        }
 
         // I know it's crazy but yes, dir can be changed by our parent's
         // commit (if predecessor is child)
@@ -3231,7 +3253,10 @@ static int lfs_rawremove(lfs_t *lfs, const char *path) {
     lfs->mlist = dir.next;
     if (lfs_tag_type3(tag) == LFS_TYPE_DIR) {
         // fix orphan
-        lfs_fs_preporphans(lfs, -1);
+        err = lfs_fs_preporphans(lfs, -1);
+        if (err) {
+            return err;
+        }
 
         err = lfs_fs_pred(lfs, dir.m.pair, &cwd);
         if (err) {
@@ -3317,7 +3342,10 @@ static int lfs_rawrename(lfs_t *lfs, const char *oldpath, const char *newpath) {
         }
 
         // mark fs as orphaned
-        lfs_fs_preporphans(lfs, +1);
+        err = lfs_fs_preporphans(lfs, +1);
+        if (err) {
+            return err;
+        }
 
         // I know it's crazy but yes, dir can be changed by our parent's
         // commit (if predecessor is child)
@@ -3360,7 +3388,10 @@ static int lfs_rawrename(lfs_t *lfs, const char *oldpath, const char *newpath) {
     lfs->mlist = prevdir.next;
     if (prevtag != LFS_ERR_NOENT && lfs_tag_type3(prevtag) == LFS_TYPE_DIR) {
         // fix orphan
-        lfs_fs_preporphans(lfs, -1);
+        err = lfs_fs_preporphans(lfs, -1);
+        if (err) {
+            return err;
+        }
 
         err = lfs_fs_pred(lfs, prevdir.m.pair, &newcwd);
         if (err) {
@@ -3541,6 +3572,8 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
         lfs->attr_max = LFS_ATTR_MAX;
     }
 
+    LFS_ASSERT(lfs->cfg->metadata_max <= lfs->cfg->block_size);
+
     // setup default state
     lfs->root[0] = LFS_BLOCK_NULL;
     lfs->root[1] = LFS_BLOCK_NULL;
@@ -3621,12 +3654,6 @@ static int lfs_rawformat(lfs_t *lfs, const struct lfs_config *cfg) {
             goto cleanup;
         }
 
-        // sanity check that fetch works
-        err = lfs_dir_fetch(lfs, &root, (const lfs_block_t[2]){0, 1});
-        if (err) {
-            goto cleanup;
-        }
-
         // force compaction to prevent accidentally mounting any
         // older version of littlefs that may live on disk
         root.erased = false;
@@ -3634,6 +3661,12 @@ static int lfs_rawformat(lfs_t *lfs, const struct lfs_config *cfg) {
         if (err) {
             goto cleanup;
         }
+
+        // sanity check that fetch works
+        err = lfs_dir_fetch(lfs, &root, (const lfs_block_t[2]){0, 1});
+        if (err) {
+            goto cleanup;
+        }
     }
 
 cleanup:
@@ -3834,7 +3867,7 @@ int lfs_fs_rawtraverse(lfs_t *lfs,
                 if (err) {
                     return err;
                 }
-            } else if (includeorphans && 
+            } else if (includeorphans &&
                     lfs_tag_type3(tag) == LFS_TYPE_DIRSTRUCT) {
                 for (int i = 0; i < 2; i++) {
                     err = cb(data, (&ctz.head)[i]);
@@ -3991,7 +4024,10 @@ static int lfs_fs_relocate(lfs_t *lfs,
 
     if (tag != LFS_ERR_NOENT) {
         // update disk, this creates a desync
-        lfs_fs_preporphans(lfs, +1);
+        int err = lfs_fs_preporphans(lfs, +1);
+        if (err) {
+            return err;
+        }
 
         // fix pending move in this pair? this looks like an optimization but
         // is in fact _required_ since relocating may outdate the move.
@@ -4008,7 +4044,7 @@ static int lfs_fs_relocate(lfs_t *lfs,
         }
 
         lfs_pair_tole32(newpair);
-        int err = lfs_dir_commit(lfs, &parent, LFS_MKATTRS(
+        err = lfs_dir_commit(lfs, &parent, LFS_MKATTRS(
                 {LFS_MKTAG_IF(moveid != 0x3ff,
                     LFS_TYPE_DELETE, moveid, 0), NULL},
                 {tag, newpair}));
@@ -4018,7 +4054,10 @@ static int lfs_fs_relocate(lfs_t *lfs,
         }
 
         // next step, clean up orphans
-        lfs_fs_preporphans(lfs, -1);
+        err = lfs_fs_preporphans(lfs, -1);
+        if (err) {
+            return err;
+        }
     }
 
     // find pred
@@ -4057,11 +4096,13 @@ static int lfs_fs_relocate(lfs_t *lfs,
 #endif
 
 #ifndef LFS_READONLY
-static void lfs_fs_preporphans(lfs_t *lfs, int8_t orphans) {
+static int lfs_fs_preporphans(lfs_t *lfs, int8_t orphans) {
     LFS_ASSERT(lfs_tag_size(lfs->gstate.tag) > 0 || orphans >= 0);
     lfs->gstate.tag += orphans;
     lfs->gstate.tag = ((lfs->gstate.tag & ~LFS_MKTAG(0x800, 0, 0)) |
             ((uint32_t)lfs_gstate_hasorphans(&lfs->gstate) << 31));
+
+    return 0;
 }
 #endif
 
@@ -4178,8 +4219,7 @@ static int lfs_fs_deorphan(lfs_t *lfs) {
     }
 
     // mark orphans as fixed
-    lfs_fs_preporphans(lfs, -lfs_gstate_getorphans(&lfs->gstate));
-    return 0;
+    return lfs_fs_preporphans(lfs, -lfs_gstate_getorphans(&lfs->gstate));
 }
 #endif
 
@@ -4728,7 +4768,7 @@ static int lfs_rawmigrate(lfs_t *lfs, const struct lfs_config *cfg) {
 
                 lfs1_entry_tole32(&entry1.d);
                 err = lfs_dir_commit(lfs, &dir2, LFS_MKATTRS(
-                        {LFS_MKTAG(LFS_TYPE_CREATE, id, 0)},
+                        {LFS_MKTAG(LFS_TYPE_CREATE, id, 0), NULL},
                         {LFS_MKTAG_IF_ELSE(isdir,
                             LFS_TYPE_DIR, id, entry1.d.nlen,
                             LFS_TYPE_REG, id, entry1.d.nlen),
@@ -4833,7 +4873,7 @@ static int lfs_rawmigrate(lfs_t *lfs, const struct lfs_config *cfg) {
 
         lfs_superblock_tole32(&superblock);
         err = lfs_dir_commit(lfs, &dir2, LFS_MKATTRS(
-                {LFS_MKTAG(LFS_TYPE_CREATE, 0, 0)},
+                {LFS_MKTAG(LFS_TYPE_CREATE, 0, 0), NULL},
                 {LFS_MKTAG(LFS_TYPE_SUPERBLOCK, 0, 8), "littlefs"},
                 {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
                     &superblock}));

+ 8 - 2
src/lfs.h

@@ -22,7 +22,7 @@ extern "C"
 // Software library version
 // Major (top-nibble), incremented on backwards incompatible changes
 // Minor (bottom-nibble), incremented on feature additions
-#define LFS_VERSION 0x00020003
+#define LFS_VERSION 0x00020004
 #define LFS_VERSION_MAJOR (0xffff & (LFS_VERSION >> 16))
 #define LFS_VERSION_MINOR (0xffff & (LFS_VERSION >>  0))
 
@@ -207,7 +207,7 @@ struct lfs_config {
     // Number of erasable blocks on the device.
     lfs_size_t block_count;
 
-    // Number of erase cycles before littlefs evicts metadata logs and moves 
+    // Number of erase cycles before littlefs evicts metadata logs and moves
     // the metadata to another block. Suggested values are in the
     // range 100-1000, with large values having better performance at the cost
     // of less consistent wear distribution.
@@ -256,6 +256,12 @@ struct lfs_config {
     // larger attributes size but must be <= LFS_ATTR_MAX. Defaults to
     // LFS_ATTR_MAX when zero.
     lfs_size_t attr_max;
+
+    // Optional upper limit on total space given to metadata pairs in bytes. On
+    // devices with large blocks (e.g. 128kB) setting this to a low size (2-8kB)
+    // can help bound the metadata compaction time. Must be <= block_size.
+    // Defaults to block_size when zero.
+    lfs_size_t metadata_max;
 };
 
 // File info structure

+ 10 - 0
src/lfs_util.h

@@ -49,6 +49,7 @@ extern "C"
 // code footprint
 
 // Logging functions
+#ifndef LFS_TRACE
 #ifdef LFS_YES_TRACE
 #define LFS_TRACE_(fmt, ...) \
     printf("%s:%d:trace: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
@@ -56,7 +57,9 @@ extern "C"
 #else
 #define LFS_TRACE(...)
 #endif
+#endif
 
+#ifndef LFS_DEBUG
 #ifndef LFS_NO_DEBUG
 #define LFS_DEBUG_(fmt, ...) \
     printf("%s:%d:debug: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
@@ -64,7 +67,9 @@ extern "C"
 #else
 #define LFS_DEBUG(...)
 #endif
+#endif
 
+#ifndef LFS_WARN
 #ifndef LFS_NO_WARN
 #define LFS_WARN_(fmt, ...) \
     printf("%s:%d:warn: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
@@ -72,7 +77,9 @@ extern "C"
 #else
 #define LFS_WARN(...)
 #endif
+#endif
 
+#ifndef LFS_ERROR
 #ifndef LFS_NO_ERROR
 #define LFS_ERROR_(fmt, ...) \
     printf("%s:%d:error: " fmt "%s\n", __FILE__, __LINE__, __VA_ARGS__)
@@ -80,13 +87,16 @@ extern "C"
 #else
 #define LFS_ERROR(...)
 #endif
+#endif
 
 // Runtime assertions
+#ifndef LFS_ASSERT
 #ifndef LFS_NO_ASSERT
 #define LFS_ASSERT(test) assert(test)
 #else
 #define LFS_ASSERT(test)
 #endif
+#endif
 
 
 // Builtin functions, these may be replaced by more efficient