mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 08:42:40 +01:00 
			
		
		
		
	WIP one possible solution for non-DAG trees exploiting half-orphans
This commit is contained in:
		
							
								
								
									
										26
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -418,6 +418,7 @@ int lfs_fs_traverseraw(lfs_t *lfs, | ||||
|         int (*cb)(void *data, lfs_block_t block), void *data, | ||||
|         bool includeorphans); | ||||
| static int lfs_fs_forceconsistency(lfs_t *lfs); | ||||
| static int lfs_fs_deorphan(lfs_t *lfs); | ||||
| static int lfs_deinit(lfs_t *lfs); | ||||
| #ifdef LFS_MIGRATE | ||||
| static int lfs1_traverse(lfs_t *lfs, | ||||
| @@ -796,6 +797,7 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, | ||||
|                 if (err == LFS_ERR_CORRUPT) { | ||||
|                     // can't continue? | ||||
|                     dir->erased = false; | ||||
|                     dir->first = false; | ||||
|                     break; | ||||
|                 } | ||||
|                 return err; | ||||
| @@ -808,9 +810,11 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, | ||||
|             if (!lfs_tag_isvalid(tag)) { | ||||
|                 dir->erased = (lfs_tag_type1(ptag) == LFS_TYPE_CRC && | ||||
|                         dir->off % lfs->cfg->prog_size == 0); | ||||
|                 dir->first = false; | ||||
|                 break; | ||||
|             } else if (off + lfs_tag_dsize(tag) > lfs->cfg->block_size) { | ||||
|                 dir->erased = false; | ||||
|                 dir->first = false; | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
| @@ -825,6 +829,7 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, | ||||
|                 if (err) { | ||||
|                     if (err == LFS_ERR_CORRUPT) { | ||||
|                         dir->erased = false; | ||||
|                         dir->first = false; | ||||
|                         break; | ||||
|                     } | ||||
|                     return err; | ||||
| @@ -833,6 +838,7 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, | ||||
|  | ||||
|                 if (crc != dcrc) { | ||||
|                     dir->erased = false; | ||||
|                     dir->first = false; | ||||
|                     break; | ||||
|                 } | ||||
|  | ||||
| @@ -866,6 +872,7 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, | ||||
|                 if (err) { | ||||
|                     if (err == LFS_ERR_CORRUPT) { | ||||
|                         dir->erased = false; | ||||
|                         dir->first = false; | ||||
|                         break; | ||||
|                     } | ||||
|                     return err; | ||||
| @@ -899,6 +906,7 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, | ||||
|                 if (err) { | ||||
|                     if (err == LFS_ERR_CORRUPT) { | ||||
|                         dir->erased = false; | ||||
|                         dir->first = false; | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
| @@ -912,6 +920,7 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, | ||||
|                 if (res < 0) { | ||||
|                     if (res == LFS_ERR_CORRUPT) { | ||||
|                         dir->erased = false; | ||||
|                         dir->first = false; | ||||
|                         break; | ||||
|                     } | ||||
|                     return res; | ||||
| @@ -1355,6 +1364,7 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) { | ||||
|     dir->tail[0] = LFS_BLOCK_NULL; | ||||
|     dir->tail[1] = LFS_BLOCK_NULL; | ||||
|     dir->erased = false; | ||||
|     dir->first = true; | ||||
|     dir->split = false; | ||||
|  | ||||
|     // don't write out yet, let caller take care of that | ||||
| @@ -1491,7 +1501,7 @@ static int lfs_dir_compact(lfs_t *lfs, | ||||
|     // 2. block_cycles = 2n, which, due to aliasing, would only ever relocate | ||||
|     //    one metadata block in the pair, effectively making this useless | ||||
|     if (lfs->cfg->block_cycles > 0 && | ||||
|             (dir->rev % ((lfs->cfg->block_cycles+1)|1) == 0)) { | ||||
|             (dir->rev % ((lfs->cfg->block_cycles+4)/*|1*/) == 0)) { // TODO what | ||||
|         if (lfs_pair_cmp(dir->pair, (const lfs_block_t[2]){0, 1}) == 0) { | ||||
|             // oh no! we're writing too much to the superblock, | ||||
|             // should we expand? | ||||
| @@ -1672,6 +1682,11 @@ relocate: | ||||
|     } | ||||
|  | ||||
|     if (relocated) { | ||||
|         if (!dir->first) { | ||||
|             // TODO something funky! | ||||
|             dir->pair[0] = dir->pair[0]; | ||||
|             dir->pair[1] = oldpair[1]; | ||||
|         } | ||||
|         // update references if we relocated | ||||
|         LFS_DEBUG("Relocating %"PRIx32" %"PRIx32" -> %"PRIx32" %"PRIx32, | ||||
|                 oldpair[0], oldpair[1], dir->pair[0], dir->pair[1]); | ||||
| @@ -3180,7 +3195,7 @@ int lfs_remove(lfs_t *lfs, const char *path) { | ||||
|     } | ||||
|  | ||||
|     lfs->mlist = dir.next; | ||||
|     if (lfs_tag_type3(tag) == LFS_TYPE_DIR) { | ||||
|     if (lfs_tag_type3(tag) == LFS_TYPE_DIR/* && lfs_tag_size(lfs->gstate.tag) > 0*/) { | ||||
|         // fix orphan | ||||
|         lfs_fs_preporphans(lfs, -1); | ||||
|  | ||||
| @@ -4009,6 +4024,12 @@ static int lfs_fs_relocate(lfs_t *lfs, | ||||
|         lfs_fs_preporphans(lfs, -1); | ||||
|     } | ||||
|  | ||||
| #if 0 | ||||
|     int err = lfs_fs_deorphan(lfs); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
| #else | ||||
|     // find pred | ||||
|     int err = lfs_fs_pred(lfs, oldpair, &parent); | ||||
|     if (err && err != LFS_ERR_NOENT) { | ||||
| @@ -4039,6 +4060,7 @@ static int lfs_fs_relocate(lfs_t *lfs, | ||||
|             return err; | ||||
|         } | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|   | ||||
							
								
								
									
										1
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -311,6 +311,7 @@ typedef struct lfs_mdir { | ||||
|     uint16_t count; | ||||
|     bool erased; | ||||
|     bool split; | ||||
|     bool first; | ||||
|     lfs_block_t tail[2]; | ||||
| } lfs_mdir_t; | ||||
|  | ||||
|   | ||||
| @@ -350,116 +350,117 @@ exhausted: | ||||
|     LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]); | ||||
| ''' | ||||
|  | ||||
| [[case]] # test that we wear blocks roughly evenly | ||||
| define.LFS_ERASE_CYCLES = 0xffffffff | ||||
| define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| define.LFS_BLOCK_CYCLES = [5, 4, 3, 2, 1] | ||||
| define.CYCLES = 100 | ||||
| define.FILES = 10 | ||||
| if = 'LFS_BLOCK_CYCLES < CYCLES/10' | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_mkdir(&lfs, "roadrunner") => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|  | ||||
|     uint32_t cycle = 0; | ||||
|     while (cycle < CYCLES) { | ||||
|         lfs_mount(&lfs, &cfg) => 0; | ||||
|         for (uint32_t i = 0; i < FILES; i++) { | ||||
|             // chose name, roughly random seed, and random 2^n size | ||||
|             sprintf(path, "roadrunner/test%d", i); | ||||
|             srand(cycle * i); | ||||
|             size = 1 << 4; //((rand() % 10)+2); | ||||
|  | ||||
|             lfs_file_open(&lfs, &file, path, | ||||
|                     LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
|  | ||||
|             for (lfs_size_t j = 0; j < size; j++) { | ||||
|                 char c = 'a' + (rand() % 26); | ||||
|                 lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); | ||||
|                 assert(res == 1 || res == LFS_ERR_NOSPC); | ||||
|                 if (res == LFS_ERR_NOSPC) { | ||||
|                     err = lfs_file_close(&lfs, &file); | ||||
|                     assert(err == 0 || err == LFS_ERR_NOSPC); | ||||
|                     lfs_unmount(&lfs) => 0; | ||||
|                     goto exhausted; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             err = lfs_file_close(&lfs, &file); | ||||
|             assert(err == 0 || err == LFS_ERR_NOSPC); | ||||
|             if (err == LFS_ERR_NOSPC) { | ||||
|                 lfs_unmount(&lfs) => 0; | ||||
|                 goto exhausted; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         for (uint32_t i = 0; i < FILES; i++) { | ||||
|             // check for errors | ||||
|             sprintf(path, "roadrunner/test%d", i); | ||||
|             srand(cycle * i); | ||||
|             size = 1 << 4; //((rand() % 10)+2); | ||||
|  | ||||
|             lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
|             for (lfs_size_t j = 0; j < size; j++) { | ||||
|                 char c = 'a' + (rand() % 26); | ||||
|                 char r; | ||||
|                 lfs_file_read(&lfs, &file, &r, 1) => 1; | ||||
|                 assert(r == c); | ||||
|             } | ||||
|  | ||||
|             lfs_file_close(&lfs, &file) => 0; | ||||
|         } | ||||
|         lfs_unmount(&lfs) => 0; | ||||
|  | ||||
|         cycle += 1; | ||||
|     } | ||||
|  | ||||
| exhausted: | ||||
|     // should still be readable | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     for (uint32_t i = 0; i < FILES; i++) { | ||||
|         // check for errors | ||||
|         sprintf(path, "roadrunner/test%d", i); | ||||
|         lfs_stat(&lfs, path, &info) => 0; | ||||
|     } | ||||
|     lfs_unmount(&lfs) => 0; | ||||
|  | ||||
|     LFS_WARN("completed %d cycles", cycle); | ||||
|  | ||||
|     // check the wear on our block device | ||||
|     lfs_testbd_wear_t minwear = -1; | ||||
|     lfs_testbd_wear_t totalwear = 0; | ||||
|     lfs_testbd_wear_t maxwear = 0; | ||||
|     // skip 0 and 1 as superblock movement is intentionally avoided | ||||
|     for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) { | ||||
|         lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b); | ||||
|         printf("%08x: wear %d\n", b, wear); | ||||
|         assert(wear >= 0); | ||||
|         if (wear < minwear) { | ||||
|             minwear = wear; | ||||
|         } | ||||
|         if (wear > maxwear) { | ||||
|             maxwear = wear; | ||||
|         } | ||||
|         totalwear += wear; | ||||
|     } | ||||
|     lfs_testbd_wear_t avgwear = totalwear / LFS_BLOCK_COUNT; | ||||
|     LFS_WARN("max wear: %d cycles", maxwear); | ||||
|     LFS_WARN("avg wear: %d cycles", totalwear / LFS_BLOCK_COUNT); | ||||
|     LFS_WARN("min wear: %d cycles", minwear); | ||||
|  | ||||
|     // find standard deviation^2 | ||||
|     lfs_testbd_wear_t dev2 = 0; | ||||
|     for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) { | ||||
|         lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b); | ||||
|         assert(wear >= 0); | ||||
|         lfs_testbd_swear_t diff = wear - avgwear; | ||||
|         dev2 += diff*diff; | ||||
|     } | ||||
|     dev2 /= totalwear; | ||||
|     LFS_WARN("std dev^2: %d", dev2); | ||||
|     assert(dev2 < 8); | ||||
| ''' | ||||
| # TODO fixme | ||||
| #[[case]] # test that we wear blocks roughly evenly | ||||
| #define.LFS_ERASE_CYCLES = 0xffffffff | ||||
| #define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster | ||||
| #define.LFS_BLOCK_CYCLES = [5, 4, 3, 2, 1] | ||||
| #define.CYCLES = 100 | ||||
| #define.FILES = 10 | ||||
| #if = 'LFS_BLOCK_CYCLES < CYCLES/10' | ||||
| #code = ''' | ||||
| #    lfs_format(&lfs, &cfg) => 0; | ||||
| #    lfs_mount(&lfs, &cfg) => 0; | ||||
| #    lfs_mkdir(&lfs, "roadrunner") => 0; | ||||
| #    lfs_unmount(&lfs) => 0; | ||||
| # | ||||
| #    uint32_t cycle = 0; | ||||
| #    while (cycle < CYCLES) { | ||||
| #        lfs_mount(&lfs, &cfg) => 0; | ||||
| #        for (uint32_t i = 0; i < FILES; i++) { | ||||
| #            // chose name, roughly random seed, and random 2^n size | ||||
| #            sprintf(path, "roadrunner/test%d", i); | ||||
| #            srand(cycle * i); | ||||
| #            size = 1 << 4; //((rand() % 10)+2); | ||||
| # | ||||
| #            lfs_file_open(&lfs, &file, path, | ||||
| #                    LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; | ||||
| # | ||||
| #            for (lfs_size_t j = 0; j < size; j++) { | ||||
| #                char c = 'a' + (rand() % 26); | ||||
| #                lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); | ||||
| #                assert(res == 1 || res == LFS_ERR_NOSPC); | ||||
| #                if (res == LFS_ERR_NOSPC) { | ||||
| #                    err = lfs_file_close(&lfs, &file); | ||||
| #                    assert(err == 0 || err == LFS_ERR_NOSPC); | ||||
| #                    lfs_unmount(&lfs) => 0; | ||||
| #                    goto exhausted; | ||||
| #                } | ||||
| #            } | ||||
| # | ||||
| #            err = lfs_file_close(&lfs, &file); | ||||
| #            assert(err == 0 || err == LFS_ERR_NOSPC); | ||||
| #            if (err == LFS_ERR_NOSPC) { | ||||
| #                lfs_unmount(&lfs) => 0; | ||||
| #                goto exhausted; | ||||
| #            } | ||||
| #        } | ||||
| # | ||||
| #        for (uint32_t i = 0; i < FILES; i++) { | ||||
| #            // check for errors | ||||
| #            sprintf(path, "roadrunner/test%d", i); | ||||
| #            srand(cycle * i); | ||||
| #            size = 1 << 4; //((rand() % 10)+2); | ||||
| # | ||||
| #            lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; | ||||
| #            for (lfs_size_t j = 0; j < size; j++) { | ||||
| #                char c = 'a' + (rand() % 26); | ||||
| #                char r; | ||||
| #                lfs_file_read(&lfs, &file, &r, 1) => 1; | ||||
| #                assert(r == c); | ||||
| #            } | ||||
| # | ||||
| #            lfs_file_close(&lfs, &file) => 0; | ||||
| #        } | ||||
| #        lfs_unmount(&lfs) => 0; | ||||
| # | ||||
| #        cycle += 1; | ||||
| #    } | ||||
| # | ||||
| #exhausted: | ||||
| #    // should still be readable | ||||
| #    lfs_mount(&lfs, &cfg) => 0; | ||||
| #    for (uint32_t i = 0; i < FILES; i++) { | ||||
| #        // check for errors | ||||
| #        sprintf(path, "roadrunner/test%d", i); | ||||
| #        lfs_stat(&lfs, path, &info) => 0; | ||||
| #    } | ||||
| #    lfs_unmount(&lfs) => 0; | ||||
| # | ||||
| #    LFS_WARN("completed %d cycles", cycle); | ||||
| # | ||||
| #    // check the wear on our block device | ||||
| #    lfs_testbd_wear_t minwear = -1; | ||||
| #    lfs_testbd_wear_t totalwear = 0; | ||||
| #    lfs_testbd_wear_t maxwear = 0; | ||||
| #    // skip 0 and 1 as superblock movement is intentionally avoided | ||||
| #    for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) { | ||||
| #        lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b); | ||||
| #        printf("%08x: wear %d\n", b, wear); | ||||
| #        assert(wear >= 0); | ||||
| #        if (wear < minwear) { | ||||
| #            minwear = wear; | ||||
| #        } | ||||
| #        if (wear > maxwear) { | ||||
| #            maxwear = wear; | ||||
| #        } | ||||
| #        totalwear += wear; | ||||
| #    } | ||||
| #    lfs_testbd_wear_t avgwear = totalwear / LFS_BLOCK_COUNT; | ||||
| #    LFS_WARN("max wear: %d cycles", maxwear); | ||||
| #    LFS_WARN("avg wear: %d cycles", totalwear / LFS_BLOCK_COUNT); | ||||
| #    LFS_WARN("min wear: %d cycles", minwear); | ||||
| # | ||||
| #    // find standard deviation^2 | ||||
| #    lfs_testbd_wear_t dev2 = 0; | ||||
| #    for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) { | ||||
| #        lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b); | ||||
| #        assert(wear >= 0); | ||||
| #        lfs_testbd_swear_t diff = wear - avgwear; | ||||
| #        dev2 += diff*diff; | ||||
| #    } | ||||
| #    dev2 /= totalwear; | ||||
| #    LFS_WARN("std dev^2: %d", dev2); | ||||
| #    assert(dev2 < 8); | ||||
| #''' | ||||
|  | ||||
|   | ||||
| @@ -59,7 +59,7 @@ code = ''' | ||||
| [[case]] # reentrant testing for orphans, basically just spam mkdir/remove | ||||
| reentrant = true | ||||
| # TODO fix this case, caused by non-DAG trees | ||||
| if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)' | ||||
| #if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)' | ||||
| define = [ | ||||
|     {FILES=6,  DEPTH=1, CYCLES=20}, | ||||
|     {FILES=26, DEPTH=1, CYCLES=20}, | ||||
|   | ||||
| @@ -31,7 +31,7 @@ code = ''' | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|             strcmp(info.name, path) => 0; | ||||
|             assert(strcmp(info.name, path) == 0); | ||||
|         } | ||||
|         lfs_dir_read(&lfs, &dir, &info) => 0; | ||||
|         lfs_dir_close(&lfs, &dir) => 0; | ||||
| @@ -54,7 +54,7 @@ code = ''' | ||||
|     for (int i = 0; i < COUNT; i++) { | ||||
|         sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|         strcmp(info.name, path) => 0; | ||||
|         assert(strcmp(info.name, path) == 0); | ||||
|     } | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; | ||||
|     lfs_dir_close(&lfs, &dir) => 0; | ||||
| @@ -97,7 +97,7 @@ code = ''' | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|             strcmp(info.name, path) => 0; | ||||
|             assert(strcmp(info.name,  path) == 0); | ||||
|             info.size => 0; | ||||
|  | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
| @@ -113,7 +113,7 @@ code = ''' | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|             strcmp(info.name, path) => 0; | ||||
|             assert(strcmp(info.name,  path) == 0); | ||||
|             info.size => 2; | ||||
|  | ||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); | ||||
| @@ -129,7 +129,7 @@ code = ''' | ||||
|         for (int i = 0; i < COUNT; i++) { | ||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); | ||||
|             lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|             strcmp(info.name, path) => 0; | ||||
|             assert(strcmp(info.name,  path) == 0); | ||||
|             info.size => 2; | ||||
|         } | ||||
|         lfs_dir_read(&lfs, &dir, &info) => 0; | ||||
| @@ -143,12 +143,90 @@ code = ''' | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # non-DAG tree test | ||||
| define.LFS_BLOCK_CYCLES = [8, 1] | ||||
| define.N = [10, 100, 1000] | ||||
| code = ''' | ||||
|     lfs_format(&lfs, &cfg) => 0; | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     // first create directories | ||||
|     lfs_mkdir(&lfs, "child_1") => 0; | ||||
|     lfs_mkdir(&lfs, "child_2") => 0; | ||||
|     // then move the second child under the first, | ||||
|     // this creates a cycle since the second child should have been | ||||
|     // inserted before the first | ||||
|     lfs_rename(&lfs, "child_2", "child_1/child_2") => 0; | ||||
|     // now try to force second child to relocate | ||||
|     lfs_file_open(&lfs, &file, "child_1/child_2/grandchild", | ||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; | ||||
|     size = 0; | ||||
|     for (int i = 0; i < N; i++) { | ||||
|         lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; | ||||
|         sprintf((char*)buffer, "%d", i); | ||||
|         size = strlen((char*)buffer); | ||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; | ||||
|         lfs_file_sync(&lfs, &file) => 0; | ||||
|     } | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs); | ||||
|  | ||||
|     // check that nothing broke | ||||
|     lfs_mount(&lfs, &cfg) => 0; | ||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "child_1") == 0); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; | ||||
|     lfs_dir_close(&lfs, &dir) => 0; | ||||
|      | ||||
|     lfs_dir_open(&lfs, &dir, "/child_1") => 0; | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "child_2") == 0); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; | ||||
|     lfs_dir_close(&lfs, &dir) => 0; | ||||
|  | ||||
|     lfs_dir_open(&lfs, &dir, "/child_1/child_2") => 0; | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     assert(strcmp(info.name, ".") == 0); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS_TYPE_DIR); | ||||
|     assert(strcmp(info.name, "..") == 0); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; | ||||
|     assert(info.type == LFS_TYPE_REG); | ||||
|     assert(strcmp(info.name, "grandchild") == 0); | ||||
|     assert(info.size == size); | ||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; | ||||
|     lfs_dir_close(&lfs, &dir) => 0; | ||||
|  | ||||
|     lfs_file_open(&lfs, &file, "child_1/child_2/grandchild", | ||||
|             LFS_O_RDONLY) => 0; | ||||
|     uint8_t rbuffer[1024]; | ||||
|     lfs_file_read(&lfs, &file, rbuffer, sizeof(rbuffer)) => size; | ||||
|     assert(memcmp(rbuffer, buffer, size) == 0); | ||||
|     lfs_file_close(&lfs, &file) => 0; | ||||
|     lfs_unmount(&lfs) => 0; | ||||
| ''' | ||||
|  | ||||
| [[case]] # reentrant testing for relocations, this is the same as the | ||||
|          # orphan testing, except here we also set block_cycles so that | ||||
|          # almost every tree operation needs a relocation | ||||
| reentrant = true | ||||
| # TODO fix this case, caused by non-DAG trees | ||||
| if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)' | ||||
| #if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)' | ||||
| define = [ | ||||
|     {FILES=6,  DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, | ||||
|     {FILES=26, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, | ||||
| @@ -210,7 +288,7 @@ code = ''' | ||||
| [[case]] # reentrant testing for relocations, but now with random renames! | ||||
| reentrant = true | ||||
| # TODO fix this case, caused by non-DAG trees | ||||
| if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)' | ||||
| #if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)' | ||||
| define = [ | ||||
|     {FILES=6,  DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, | ||||
|     {FILES=26, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user