Bläddra i källkod

Merge pull request #966 from BrianPugh/fix-divide-by-zero-full-filesystem

Fix DivideByZero exception when filesystem is completely full.
Christopher Haster 1 år sedan
förälder
incheckning
68d28b5114
3 ändrade filer med 62 tillägg och 25 borttagningar
  1. 1 1
      lfs.c
  2. 9 7
      lfs.h
  3. 52 17
      tests/test_alloc.toml

+ 1 - 1
lfs.c

@@ -688,7 +688,7 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) {
         if (lfs->lookahead.ckpoint <= 0) {
             LFS_ERROR("No more free space 0x%"PRIx32,
                     (lfs->lookahead.start + lfs->lookahead.next)
-                        % lfs->cfg->block_count);
+                        % lfs->block_count);
             return LFS_ERR_NOSPC;
         }
 

+ 9 - 7
lfs.h

@@ -59,7 +59,8 @@ typedef uint32_t lfs_block_t;
 #endif
 
 // Maximum size of custom attributes in bytes, may be redefined, but there is
-// no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022.
+// no real benefit to using a smaller LFS_ATTR_MAX. Limited to <= 1022. Stored
+// in superblock and must be respected by other littlefs drivers.
 #ifndef LFS_ATTR_MAX
 #define LFS_ATTR_MAX 1022
 #endif
@@ -203,7 +204,8 @@ struct lfs_config {
     // program sizes.
     lfs_size_t block_size;
 
-    // Number of erasable blocks on the device.
+    // Number of erasable blocks on the device. Defaults to block_count stored
+    // on disk when zero.
     lfs_size_t block_count;
 
     // Number of erase cycles before littlefs evicts metadata logs and moves
@@ -252,18 +254,18 @@ struct lfs_config {
 
     // Optional upper limit on length of file names in bytes. No downside for
     // larger names except the size of the info struct which is controlled by
-    // the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX when zero. Stored in
-    // superblock and must be respected by other littlefs drivers.
+    // the LFS_NAME_MAX define. Defaults to LFS_NAME_MAX or name_max stored on
+    // disk when zero.
     lfs_size_t name_max;
 
     // Optional upper limit on files in bytes. No downside for larger files
-    // but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX when zero. Stored
-    // in superblock and must be respected by other littlefs drivers.
+    // but must be <= LFS_FILE_MAX. Defaults to LFS_FILE_MAX or file_max stored
+    // on disk when zero.
     lfs_size_t file_max;
 
     // Optional upper limit on custom attributes in bytes. No downside for
     // larger attributes size but must be <= LFS_ATTR_MAX. Defaults to
-    // LFS_ATTR_MAX when zero.
+    // LFS_ATTR_MAX or attr_max stored on disk when zero.
     lfs_size_t attr_max;
 
     // Optional upper limit on total space given to metadata pairs in bytes. On

+ 52 - 17
tests/test_alloc.toml

@@ -8,17 +8,22 @@ defines.FILES = 3
 defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
 defines.GC = [false, true]
 defines.COMPACT_THRESH = ['-1', '0', 'BLOCK_SIZE/2']
+defines.INFER_BC = [false, true]
 code = '''
     const char *names[] = {"bacon", "eggs", "pancakes"};
     lfs_file_t files[FILES];
 
     lfs_t lfs;
     lfs_format(&lfs, cfg) => 0;
-    lfs_mount(&lfs, cfg) => 0;
+    struct lfs_config cfg_ = *cfg;
+    if (INFER_BC) {
+        cfg_.block_count = 0;
+    }
+    lfs_mount(&lfs, &cfg_) => 0;
     lfs_mkdir(&lfs, "breakfast") => 0;
     lfs_unmount(&lfs) => 0;
 
-    lfs_mount(&lfs, cfg) => 0;
+    lfs_mount(&lfs, &cfg_) => 0;
     for (int n = 0; n < FILES; n++) {
         char path[1024];
         sprintf(path, "breakfast/%s", names[n]);
@@ -39,7 +44,7 @@ code = '''
     }
     lfs_unmount(&lfs) => 0;
 
-    lfs_mount(&lfs, cfg) => 0;
+    lfs_mount(&lfs, &cfg_) => 0;
     for (int n = 0; n < FILES; n++) {
         char path[1024];
         sprintf(path, "breakfast/%s", names[n]);
@@ -62,17 +67,22 @@ defines.FILES = 3
 defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
 defines.GC = [false, true]
 defines.COMPACT_THRESH = ['-1', '0', 'BLOCK_SIZE/2']
+defines.INFER_BC = [false, true]
 code = '''
     const char *names[] = {"bacon", "eggs", "pancakes"};
 
     lfs_t lfs;
     lfs_format(&lfs, cfg) => 0;
-    lfs_mount(&lfs, cfg) => 0;
+    struct lfs_config cfg_ = *cfg;
+    if (INFER_BC) {
+        cfg_.block_count = 0;
+    }
+    lfs_mount(&lfs, &cfg_) => 0;
     lfs_mkdir(&lfs, "breakfast") => 0;
     lfs_unmount(&lfs) => 0;
 
     for (int n = 0; n < FILES; n++) {
-        lfs_mount(&lfs, cfg) => 0;
+        lfs_mount(&lfs, &cfg_) => 0;
         char path[1024];
         sprintf(path, "breakfast/%s", names[n]);
         lfs_file_t file;
@@ -91,7 +101,7 @@ code = '''
         lfs_unmount(&lfs) => 0;
     }
 
-    lfs_mount(&lfs, cfg) => 0;
+    lfs_mount(&lfs, &cfg_) => 0;
     for (int n = 0; n < FILES; n++) {
         char path[1024];
         sprintf(path, "breakfast/%s", names[n]);
@@ -113,19 +123,24 @@ code = '''
 defines.FILES = 3
 defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
 defines.CYCLES = [1, 10]
+defines.INFER_BC = [false, true]
 code = '''
     const char *names[] = {"bacon", "eggs", "pancakes"};
     lfs_file_t files[FILES];
 
     lfs_t lfs;
     lfs_format(&lfs, cfg) => 0;
+    struct lfs_config cfg_ = *cfg;
+    if (INFER_BC) {
+        cfg_.block_count = 0;
+    }
 
     for (int c = 0; c < CYCLES; c++) {
-        lfs_mount(&lfs, cfg) => 0;
+        lfs_mount(&lfs, &cfg_) => 0;
         lfs_mkdir(&lfs, "breakfast") => 0;
         lfs_unmount(&lfs) => 0;
 
-        lfs_mount(&lfs, cfg) => 0;
+        lfs_mount(&lfs, &cfg_) => 0;
         for (int n = 0; n < FILES; n++) {
             char path[1024];
             sprintf(path, "breakfast/%s", names[n]);
@@ -143,7 +158,7 @@ code = '''
         }
         lfs_unmount(&lfs) => 0;
 
-        lfs_mount(&lfs, cfg) => 0;
+        lfs_mount(&lfs, &cfg_) => 0;
         for (int n = 0; n < FILES; n++) {
             char path[1024];
             sprintf(path, "breakfast/%s", names[n]);
@@ -159,7 +174,7 @@ code = '''
         }
         lfs_unmount(&lfs) => 0;
 
-        lfs_mount(&lfs, cfg) => 0;
+        lfs_mount(&lfs, &cfg_) => 0;
         for (int n = 0; n < FILES; n++) {
             char path[1024];
             sprintf(path, "breakfast/%s", names[n]);
@@ -175,19 +190,24 @@ code = '''
 defines.FILES = 3
 defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
 defines.CYCLES = [1, 10]
+defines.INFER_BC = [false, true]
 code = '''
     const char *names[] = {"bacon", "eggs", "pancakes"};
 
     lfs_t lfs;
     lfs_format(&lfs, cfg) => 0;
+    struct lfs_config cfg_ = *cfg;
+    if (INFER_BC) {
+        cfg_.block_count = 0;
+    }
 
     for (int c = 0; c < CYCLES; c++) {
-        lfs_mount(&lfs, cfg) => 0;
+        lfs_mount(&lfs, &cfg_) => 0;
         lfs_mkdir(&lfs, "breakfast") => 0;
         lfs_unmount(&lfs) => 0;
 
         for (int n = 0; n < FILES; n++) {
-            lfs_mount(&lfs, cfg) => 0;
+            lfs_mount(&lfs, &cfg_) => 0;
             char path[1024];
             sprintf(path, "breakfast/%s", names[n]);
             lfs_file_t file;
@@ -232,10 +252,15 @@ code = '''
 
 # exhaustion test
 [cases.test_alloc_exhaustion]
+defines.INFER_BC = [false, true]
 code = '''
     lfs_t lfs;
     lfs_format(&lfs, cfg) => 0;
-    lfs_mount(&lfs, cfg) => 0;
+    struct lfs_config cfg_ = *cfg;
+    if (INFER_BC) {
+        cfg_.block_count = 0;
+    }
+    lfs_mount(&lfs, &cfg_) => 0;
     lfs_file_t file;
     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
     size_t size = strlen("exhaustion");
@@ -263,7 +288,7 @@ code = '''
     lfs_file_close(&lfs, &file) => 0;
     lfs_unmount(&lfs) => 0;
 
-    lfs_mount(&lfs, cfg) => 0;
+    lfs_mount(&lfs, &cfg_) => 0;
     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
     size = strlen("exhaustion");
     lfs_file_size(&lfs, &file) => size;
@@ -276,10 +301,15 @@ code = '''
 # exhaustion wraparound test
 [cases.test_alloc_exhaustion_wraparound]
 defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-4)) / 3)'
+defines.INFER_BC = [false, true]
 code = '''
     lfs_t lfs;
     lfs_format(&lfs, cfg) => 0;
-    lfs_mount(&lfs, cfg) => 0;
+    struct lfs_config cfg_ = *cfg;
+    if (INFER_BC) {
+        cfg_.block_count = 0;
+    }
+    lfs_mount(&lfs, &cfg_) => 0;
 
     lfs_file_t file;
     lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT);
@@ -317,7 +347,7 @@ code = '''
     lfs_file_close(&lfs, &file) => 0;
     lfs_unmount(&lfs) => 0;
 
-    lfs_mount(&lfs, cfg) => 0;
+    lfs_mount(&lfs, &cfg_) => 0;
     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
     size = strlen("exhaustion");
     lfs_file_size(&lfs, &file) => size;
@@ -330,10 +360,15 @@ code = '''
 
 # dir exhaustion test
 [cases.test_alloc_dir_exhaustion]
+defines.INFER_BC = [false, true]
 code = '''
     lfs_t lfs;
     lfs_format(&lfs, cfg) => 0;
-    lfs_mount(&lfs, cfg) => 0;
+    struct lfs_config cfg_ = *cfg;
+    if (INFER_BC) {
+        cfg_.block_count = 0;
+    }
+    lfs_mount(&lfs, &cfg_) => 0;
 
     // find out max file size
     lfs_mkdir(&lfs, "exhaustiondir") => 0;