gbmap: Added mkgbmap and rmgbmap for enabling/disabling the gbmap
These two functions allow changing whether or not the gbmap is in use
after format:
// Enable the global on-disk block-map
//
// Returns a negative error code on failure. Does nothing if a gbmap
// already exists.
int lfs3_fs_mkgbmap(lfs3_t *lfs3);
// Disable the global on-disk block-map
//
// Returns a negative error code on failure. Does nothing if no gbmap
// is found.
int lfs3_fs_rmgbmap(lfs3_t *lfs3);
rmgbmap was easy enough, but implementing mkgbmap turned out to be
surprisingly tricky due to how gstate permeates the system:
- Even if we zero gstate when we removing the gbmap, mounting the
image on a driver that doesn't understand the gbmap results in garbage
gstate over time as mdir compacts drop unknown gdeltas.
I think this sort of implicit gdelta cleanup is a good thing, but the
possibility of garbage gstate is a bit annoying.
Example A: the dbg scripts are currently printing a bunch of warnings
for corrupt gstate that can be safely ignored.
To support recovering from garbage gstate in mkgbmap, I changed
lfs3_fs_commitgdelta to _always_ track p state even when disabled. We
already needed to do this in lfs3_fs_flush/consumegdelta anyways,
since we don't know if the gbmap is used until parsing wcompat flags.
- The commit that enables the gbmap is tricky. We need the gbmap enabled
to calculate the new gdelta, but we also need it disabled so we don't
traverse the existing gbmap_p (which may be garbage).
As a workaround I added gbmap.b_p, which is in theory redundant with
gbmap_p, but (1) avoids needing to decode gbmap_p during traversals,
and (2) allows the two to temporarily fall out-of-sync in mkgbmap.
This means we potentially have 5 (!) snaphots flying around when
rebuilding the gbmap, which is starting to get a bit silly. But this
was also motivated by gbmap_p decoding adding roughly the same amount
of RAM to lfs3_mtree_traverse_, so the total RAM usage should in
theory be roughly the same.
There might be a better solution, but this at least gets mkgbmap
working. The gbmap builds are not our most RAM senstive configurations
anyways.
---
Also added a couple more tests in test_gbmap to test these:
- test_gbmap_files
- test_gbmap_rmgbmap
- test_gbmap_mkgbmap
- test_gbmap_rmmkgbmap
- test_gbmap_mkrmgbmap
And an explicit wraparound test to test_alloc. This was loosely implied
by the nospc tests, but it's probably better to have an explicit test.
The only downside is this implementation is limited to files:
- test_alloc_wraparound_files
---
Note we are currently dealing with three different configurations:
no-gbmap (the default), yes-gbmap (LFS3_YES_GBMAP), and maybe-gbmap
(LFS3_GBMAP + LFS3_F_GBMAP at runtime).
It only makes sense to include these in maybe-gbmap mode, so this is the
only mode with a notable code increase. However these functions are
relatively cheap. The stack/ctx changes also affect yes-gbmap, but
should mostly cancel out, see above:
code stack ctx
no-gbmap before: 37168 2352 684
no-gbmap after: 37168 (+0.0%) 2352 (+0.0%) 684 (+0.0%)
code stack ctx
maybe-gbmap before: 39292 2456 800
maybe-gbmap after: 39688 (+1.0%) 2392 (-2.6%) 852 (+6.5%)
code stack ctx
yes-gbmap before: 39116 2456 800
yes-gbmap after: 39156 (+0.1%) 2392 (-2.6%) 852 (+6.5%)
This commit is contained in:
@@ -7786,10 +7786,18 @@ static void lfs3_fs_commitgdelta(lfs3_t *lfs3) {
|
||||
// keep track of the on-disk grm
|
||||
lfs3_data_fromgrm(&lfs3->grm, lfs3->grm_p);
|
||||
|
||||
// keep track of the on-disk gbmap
|
||||
#ifdef LFS3_GBMAP
|
||||
// keep track of the on-disk gbmap
|
||||
if (lfs3_f_isgbmap(lfs3->flags)) {
|
||||
// keep track of both the committed gstate and btree for
|
||||
// traversals
|
||||
lfs3->gbmap.b_p = lfs3->gbmap.b;
|
||||
lfs3_data_fromgbmap(&lfs3->gbmap, lfs3->gbmap_p);
|
||||
|
||||
// if disabled, we still want to keep track of the on-disk gstate
|
||||
// in case the user wants to re-enable the gbmap
|
||||
} else {
|
||||
lfs3_memxor(lfs3->gbmap_p, lfs3->gbmap_d, LFS3_GBMAP_DSIZE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -10387,25 +10395,12 @@ static lfs3_stag_t lfs3_mtree_traverse_(lfs3_t *lfs3, lfs3_trv_t *trv,
|
||||
== LFS3_TSTATE_GBMAP,
|
||||
false)) {
|
||||
#ifdef LFS3_GBMAP
|
||||
// decode the on-disk gbmap
|
||||
//
|
||||
// TODO this adds 64 bytes of mostly unused stack
|
||||
// to the stack hot-path, can we avoid this somehow?
|
||||
// do we care in gbmap mode?
|
||||
//
|
||||
lfs3_gbmap_t gbmap_p;
|
||||
err = lfs3_data_readgbmap(lfs3,
|
||||
&LFS3_DATA_BUF(lfs3->gbmap_p,
|
||||
LFS3_GBMAP_DSIZE),
|
||||
&gbmap_p);
|
||||
if (err) {
|
||||
LFS3_UNREACHABLE();
|
||||
}
|
||||
|
||||
// if on-disk gbmap does not match the active gbmap,
|
||||
// transition to traversing the on-disk gbmap
|
||||
if (lfs3_btree_cmp(&gbmap_p.b, &lfs3->gbmap.b) != 0) {
|
||||
trv->b.shrub = gbmap_p.b;
|
||||
if (lfs3_btree_cmp(
|
||||
&lfs3->gbmap.b_p,
|
||||
&lfs3->gbmap.b) != 0) {
|
||||
trv->b.shrub = lfs3->gbmap.b_p;
|
||||
trv->bid = -2;
|
||||
lfs3_t_settstate(&trv->b.h.flags,
|
||||
LFS3_TSTATE_GBMAP_P);
|
||||
@@ -10723,6 +10718,15 @@ eot:;
|
||||
|
||||
/// Optional on-disk block map ///
|
||||
|
||||
#if !defined(LFS3_RDONLY) && !defined(LFS3_2BONLY) && defined(LFS3_GBMAP)
|
||||
static void lfs3_gbmap_init(lfs3_gbmap_t *gbmap) {
|
||||
gbmap->window = 0;
|
||||
gbmap->known = 0;
|
||||
lfs3_btree_init(&gbmap->b);
|
||||
lfs3_btree_init(&gbmap->b_p);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(LFS3_RDONLY) && !defined(LFS3_2BONLY) && defined(LFS3_GBMAP)
|
||||
static lfs3_data_t lfs3_data_fromgbmap(const lfs3_gbmap_t *gbmap,
|
||||
uint8_t buffer[static LFS3_GBMAP_DSIZE]) {
|
||||
@@ -10775,6 +10779,8 @@ static int lfs3_data_readgbmap(lfs3_t *lfs3, lfs3_data_t *data,
|
||||
|
||||
// make sure to zero btree leaf
|
||||
lfs3_btree_discardleaf(&gbmap->b);
|
||||
// and keep track of the committed gbmap for traversals
|
||||
gbmap->b_p = gbmap->b;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -11310,8 +11316,6 @@ static lfs3_sblock_t lfs3_alloc(lfs3_t *lfs3, uint32_t flags) {
|
||||
|
||||
#if !defined(LFS3_RDONLY) && defined(LFS3_GBMAP)
|
||||
static int lfs3_alloc_rebuildgbmap(lfs3_t *lfs3) {
|
||||
// we should ckpoint before calling this
|
||||
LFS3_ASSERT(lfs3->lookahead.ckpoint == lfs3->block_count);
|
||||
LFS3_INFO("Rebuilding gbmap "
|
||||
"(gbmap %"PRId32"/%"PRId32")",
|
||||
lfs3->lookahead.gbmapped,
|
||||
@@ -15544,6 +15548,7 @@ static int lfs3_init(lfs3_t *lfs3, uint32_t flags,
|
||||
|
||||
// TODO are these zeros accomplished by flushgdelta in mountinited?
|
||||
// should the flushgdelta be dropped?
|
||||
// TODO should we just call flushgdelta here?
|
||||
|
||||
// zero gstate
|
||||
lfs3->gcksum = 0;
|
||||
@@ -15560,11 +15565,10 @@ static int lfs3_init(lfs3_t *lfs3, uint32_t flags,
|
||||
#endif
|
||||
|
||||
// setup other global gbmap state
|
||||
// TODO is this actually needed?
|
||||
#ifdef LFS3_GBMAP
|
||||
lfs3_btree_init(&lfs3->gbmap.b);
|
||||
lfs3->gbmap.window = 0;
|
||||
lfs3->gbmap.known = 0;
|
||||
lfs3_gbmap_init(&lfs3->gbmap);
|
||||
// TODO should this be in the gbmap struct?
|
||||
lfs3->lookahead.gbmapped = 0;
|
||||
lfs3_memset(lfs3->gbmap_p, 0, LFS3_GBMAP_DSIZE);
|
||||
lfs3_memset(lfs3->gbmap_d, 0, LFS3_GBMAP_DSIZE);
|
||||
#endif
|
||||
@@ -17112,6 +17116,105 @@ failed:;
|
||||
}
|
||||
#endif
|
||||
|
||||
// enable the global on-disk block-map
|
||||
#if !defined(LFs3_RDONLY) && defined(LFS3_GBMAP) && !defined(LFS3_YES_GBMAP)
|
||||
int lfs3_fs_mkgbmap(lfs3_t *lfs3) {
|
||||
// do nothing if we already have a gbmap
|
||||
if (lfs3_f_isgbmap(lfs3->flags)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// prepare our filesystem for writing
|
||||
int err = lfs3_fs_mkconsistent(lfs3);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// checkpoint the allocator
|
||||
// TODO, should lfs3_fs_mkconsistent also checkpoint the allocator?
|
||||
err = lfs3_alloc_ckpoint(lfs3);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// create an empty gbmap
|
||||
lfs3_gbmap_init(&lfs3->gbmap);
|
||||
// TODO should this be in the gbmap struct?
|
||||
lfs3->lookahead.gbmapped = 0;
|
||||
|
||||
// start with everything free, rebuilding the gbmap will populate it
|
||||
err = lfs3_gbmap_commit(lfs3, &lfs3->gbmap.b, 0, LFS3_RATTRS(
|
||||
LFS3_RATTR(LFS3_TAG_BMFREE, +lfs3->block_count)));
|
||||
if (err) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
// go ahead and mark gbmap as in-use internally
|
||||
lfs3->flags |= LFS3_F_GBMAP;
|
||||
|
||||
// checkpoint the allocator, this should trigger a rebuild
|
||||
err = lfs3_alloc_ckpoint(lfs3);
|
||||
if (err) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
// mark the gbmap as in-use on-disk while atomically committing the
|
||||
// gbmap into gstate
|
||||
lfs3_wcompat_t wcompat_ = lfs3_wcompat(lfs3);
|
||||
wcompat_ |= LFS3_WCOMPAT_GBMAP;
|
||||
|
||||
err = lfs3_mdir_commit(lfs3, &lfs3->mroot, LFS3_RATTRS(
|
||||
LFS3_RATTR_LE32(LFS3_TAG_WCOMPAT, 0, wcompat_)));
|
||||
if (err) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:;
|
||||
// if we failed clear the gbmap bit and reset the gbmap to be safe
|
||||
lfs3->flags &= ~LFS3_F_GBMAP;
|
||||
lfs3_gbmap_init(&lfs3->gbmap);
|
||||
// TODO should this be in the gbmap struct?
|
||||
lfs3->lookahead.gbmapped = 0;
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
// disable the global on-disk block-map
|
||||
#if !defined(LFs3_RDONLY) && defined(LFS3_GBMAP) && !defined(LFS3_YES_GBMAP)
|
||||
int lfs3_fs_rmgbmap(lfs3_t *lfs3) {
|
||||
// do nothing if we already don't have a gbmap
|
||||
if (!lfs3_f_isgbmap(lfs3->flags)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// prepare our filesystem for writing
|
||||
int err = lfs3_fs_mkconsistent(lfs3);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// removing the gbmap is relatively easy, we just need to mark the
|
||||
// gbmap as not in use
|
||||
//
|
||||
// this leaves garbage gdeltas around, but these should be cleaned
|
||||
// up implicitly as mdirs are compacted
|
||||
lfs3_wcompat_t wcompat_ = lfs3_wcompat(lfs3);
|
||||
wcompat_ &= ~LFS3_WCOMPAT_GBMAP;
|
||||
|
||||
err = lfs3_mdir_commit(lfs3, &lfs3->mroot, LFS3_RATTRS(
|
||||
LFS3_RATTR_LE32(LFS3_TAG_WCOMPAT, 0, wcompat_)));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// on success mark gbmap as not-in-use internally
|
||||
lfs3->flags &= ~LFS3_F_GBMAP;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/// High-level filesystem traversal ///
|
||||
|
||||
@@ -849,6 +849,7 @@ typedef struct lfs3_gbmap {
|
||||
lfs3_block_t window;
|
||||
lfs3_block_t known;
|
||||
lfs3_btree_t b;
|
||||
lfs3_btree_t b_p;
|
||||
} lfs3_gbmap_t;
|
||||
|
||||
|
||||
@@ -1413,5 +1414,21 @@ int lfs3_fs_unck(lfs3_t *lfs3, uint32_t flags);
|
||||
int lfs3_fs_grow(lfs3_t *lfs3, lfs3_size_t block_count);
|
||||
#endif
|
||||
|
||||
// Enable the global on-disk block-map
|
||||
//
|
||||
// Returns a negative error code on failure. Does nothing if a gbmap
|
||||
// already exists.
|
||||
#if !defined(LFs3_RDONLY) && defined(LFS3_GBMAP) && !defined(LFS3_YES_GBMAP)
|
||||
int lfs3_fs_mkgbmap(lfs3_t *lfs3);
|
||||
#endif
|
||||
|
||||
// Disable the global on-disk block-map
|
||||
//
|
||||
// Returns a negative error code on failure. Does nothing if no gbmap
|
||||
// is found.
|
||||
#if !defined(LFs3_RDONLY) && defined(LFS3_GBMAP) && !defined(LFS3_YES_GBMAP)
|
||||
int lfs3_fs_rmgbmap(lfs3_t *lfs3);
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+99
-7
@@ -20,7 +20,7 @@ defines.COUNT = [
|
||||
'BLOCK_COUNT/2',
|
||||
'BLOCK_COUNT/4',
|
||||
'5',
|
||||
'2',
|
||||
'FORMAT_BLOCK_COUNT',
|
||||
]
|
||||
defines.ERASE = [false, true]
|
||||
if = 'COUNT >= FORMAT_BLOCK_COUNT'
|
||||
@@ -67,7 +67,7 @@ defines.COUNT = [
|
||||
'BLOCK_COUNT/2',
|
||||
'BLOCK_COUNT/4',
|
||||
'5',
|
||||
'2',
|
||||
'FORMAT_BLOCK_COUNT',
|
||||
]
|
||||
defines.ERASE = [false, true]
|
||||
if = 'COUNT >= FORMAT_BLOCK_COUNT'
|
||||
@@ -643,10 +643,102 @@ code = '''
|
||||
'''
|
||||
|
||||
|
||||
# TODO more nospc tests (opened files? other?)
|
||||
|
||||
# nospc tests mostly test that things still work when block allocation
|
||||
# wraparound occurs
|
||||
# test that alloc can wrap around the disk
|
||||
[cases.test_alloc_wraparound_files]
|
||||
defines.COUNT = [
|
||||
'BLOCK_COUNT',
|
||||
'BLOCK_COUNT-1',
|
||||
'BLOCK_COUNT/2',
|
||||
'BLOCK_COUNT/4',
|
||||
'5',
|
||||
'FORMAT_BLOCK_COUNT',
|
||||
]
|
||||
defines.SIZE = [
|
||||
'BLOCK_SIZE',
|
||||
'2*BLOCK_SIZE',
|
||||
'8*BLOCK_SIZE',
|
||||
]
|
||||
defines.N = ['5', 'BLOCK_COUNT/2']
|
||||
defines.WRAPAROUND = 3
|
||||
if = [
|
||||
'COUNT >= FORMAT_BLOCK_COUNT',
|
||||
'COUNT >= 2*N*SIZE/BLOCK_SIZE',
|
||||
]
|
||||
code = '''
|
||||
// test various block counts
|
||||
struct lfs3_cfg cfg = *CFG;
|
||||
cfg.block_count = COUNT;
|
||||
lfs3_t lfs3;
|
||||
lfs3_format(&lfs3, LFS3_F_RDWR, &cfg) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
|
||||
// create n files repeatedly until we're sure we've wrapped around
|
||||
// a few times
|
||||
uint32_t prng = 42;
|
||||
uint32_t prng_ = prng;
|
||||
for (lfs3_size_t i = 0;
|
||||
i < (WRAPAROUND*COUNT)
|
||||
/ (N*(SIZE/BLOCK_SIZE));
|
||||
i++) {
|
||||
prng = prng_;
|
||||
for (lfs3_size_t n = 0; n < N; n++) {
|
||||
char name[256];
|
||||
sprintf(name, "file%08d", n);
|
||||
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||
}
|
||||
|
||||
lfs3_file_t file;
|
||||
lfs3_file_open(&lfs3, &file, name,
|
||||
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_TRUNC) => 0;
|
||||
lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE;
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int remount = 0; remount < 2; remount++) {
|
||||
// remount?
|
||||
if (remount) {
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
}
|
||||
|
||||
// check that our file writes worked
|
||||
prng_ = prng;
|
||||
for (lfs3_size_t i = 0; i < N; i++) {
|
||||
// check with stat
|
||||
char name[256];
|
||||
sprintf(name, "file%08d", i);
|
||||
struct lfs3_info info;
|
||||
lfs3_stat(&lfs3, name, &info) => 0;
|
||||
assert(strcmp(info.name, name) == 0);
|
||||
assert(info.type == LFS3_TYPE_REG);
|
||||
assert(info.size == SIZE);
|
||||
|
||||
// try reading the file, note we reset prng above
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||
}
|
||||
|
||||
lfs3_file_t file;
|
||||
uint8_t rbuf[SIZE];
|
||||
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
||||
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE;
|
||||
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
'''
|
||||
|
||||
|
||||
|
||||
# test that alloc works up until nospc
|
||||
[cases.test_alloc_nospc_dirs]
|
||||
defines.COUNT = [
|
||||
'BLOCK_COUNT',
|
||||
@@ -654,7 +746,7 @@ defines.COUNT = [
|
||||
'BLOCK_COUNT/2',
|
||||
'BLOCK_COUNT/4',
|
||||
'5',
|
||||
'2',
|
||||
'FORMAT_BLOCK_COUNT',
|
||||
]
|
||||
if = 'COUNT >= FORMAT_BLOCK_COUNT'
|
||||
code = '''
|
||||
@@ -728,7 +820,7 @@ defines.COUNT = [
|
||||
'BLOCK_COUNT/2',
|
||||
'BLOCK_COUNT/4',
|
||||
'5',
|
||||
'2',
|
||||
'FORMAT_BLOCK_COUNT',
|
||||
]
|
||||
defines.SIZE = [
|
||||
'0',
|
||||
|
||||
+784
-1
@@ -9,7 +9,7 @@ after = ['test_btree', 'test_mtree']
|
||||
ifdef = 'LFS3_GBMAP'
|
||||
|
||||
|
||||
# test gbmap operations
|
||||
# test low-level gbmap operations
|
||||
|
||||
# test simple set operations
|
||||
[cases.test_gbmap_set_split]
|
||||
@@ -384,3 +384,786 @@ code = '''
|
||||
free(sim);
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
'''
|
||||
|
||||
|
||||
|
||||
# test high-level gbmap operations
|
||||
|
||||
# test that the gbmap generally works
|
||||
[cases.test_gbmap_files]
|
||||
defines.COUNT = [
|
||||
'BLOCK_COUNT',
|
||||
'BLOCK_COUNT-1',
|
||||
'BLOCK_COUNT/2',
|
||||
'BLOCK_COUNT/4',
|
||||
'5',
|
||||
'3',
|
||||
]
|
||||
defines.SIZE = [
|
||||
'BLOCK_SIZE',
|
||||
'2*BLOCK_SIZE',
|
||||
'8*BLOCK_SIZE',
|
||||
]
|
||||
defines.N = ['5', 'BLOCK_COUNT/2']
|
||||
defines.WRAPAROUND = 3
|
||||
if = [
|
||||
'COUNT >= 3',
|
||||
'COUNT >= 2*N*SIZE/BLOCK_SIZE',
|
||||
]
|
||||
code = '''
|
||||
// test various block counts
|
||||
struct lfs3_cfg cfg = *CFG;
|
||||
cfg.block_count = COUNT;
|
||||
lfs3_t lfs3;
|
||||
// note the gbmap flag
|
||||
lfs3_format(&lfs3, LFS3_F_RDWR | LFS3_F_GBMAP, &cfg) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
|
||||
// check that we were formatted with the gbmap
|
||||
struct lfs3_fsinfo fsinfo;
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(fsinfo.flags & LFS3_I_GBMAP);
|
||||
|
||||
// create n files repeatedly until we're sure we've wrapped around
|
||||
// a few times
|
||||
uint32_t prng = 42;
|
||||
uint32_t prng_ = prng;
|
||||
for (lfs3_size_t i = 0;
|
||||
i < (WRAPAROUND*COUNT)
|
||||
/ (N*(SIZE/BLOCK_SIZE));
|
||||
i++) {
|
||||
prng = prng_;
|
||||
for (lfs3_size_t n = 0; n < N; n++) {
|
||||
char name[256];
|
||||
sprintf(name, "file%08d", n);
|
||||
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||
}
|
||||
|
||||
lfs3_file_t file;
|
||||
lfs3_file_open(&lfs3, &file, name,
|
||||
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_TRUNC) => 0;
|
||||
lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE;
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int remount = 0; remount < 2; remount++) {
|
||||
// remount?
|
||||
if (remount) {
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
}
|
||||
|
||||
// check that our file writes worked
|
||||
prng_ = prng;
|
||||
for (lfs3_size_t i = 0; i < N; i++) {
|
||||
// check with stat
|
||||
char name[256];
|
||||
sprintf(name, "file%08d", i);
|
||||
struct lfs3_info info;
|
||||
lfs3_stat(&lfs3, name, &info) => 0;
|
||||
assert(strcmp(info.name, name) == 0);
|
||||
assert(info.type == LFS3_TYPE_REG);
|
||||
assert(info.size == SIZE);
|
||||
|
||||
// try reading the file, note we reset prng above
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||
}
|
||||
|
||||
lfs3_file_t file;
|
||||
uint8_t rbuf[SIZE];
|
||||
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
||||
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE;
|
||||
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
'''
|
||||
|
||||
# test that we can remove the gbmap and things still work
|
||||
[cases.test_gbmap_rmgbmap]
|
||||
ifndef = 'LFS3_YES_GBMAP'
|
||||
defines.COUNT = [
|
||||
'BLOCK_COUNT',
|
||||
'BLOCK_COUNT-1',
|
||||
'BLOCK_COUNT/2',
|
||||
'BLOCK_COUNT/4',
|
||||
'5',
|
||||
'3',
|
||||
]
|
||||
defines.SIZE = [
|
||||
'BLOCK_SIZE',
|
||||
'2*BLOCK_SIZE',
|
||||
'8*BLOCK_SIZE',
|
||||
]
|
||||
defines.N = ['5', 'BLOCK_COUNT/2']
|
||||
defines.WRAPAROUND = 3
|
||||
# REMOUNT=0 => don't remount
|
||||
# REMOUNT=1 => remount after
|
||||
# REMOUNT=2 => remount before
|
||||
# REMOUNT=3 => remount both after and before
|
||||
defines.REMOUNT = [0, 1, 2, 3]
|
||||
if = [
|
||||
'COUNT >= 3',
|
||||
'COUNT >= 2*N*SIZE/BLOCK_SIZE',
|
||||
]
|
||||
code = '''
|
||||
// test various block counts
|
||||
struct lfs3_cfg cfg = *CFG;
|
||||
cfg.block_count = COUNT;
|
||||
lfs3_t lfs3;
|
||||
// note the gbmap flag
|
||||
lfs3_format(&lfs3, LFS3_F_RDWR | LFS3_F_GBMAP, &cfg) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
|
||||
// check that we were formatted with the gbmap
|
||||
struct lfs3_fsinfo fsinfo;
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(fsinfo.flags & LFS3_I_GBMAP);
|
||||
|
||||
// create n files repeatedly until we're sure we've wrapped around
|
||||
// a few times
|
||||
uint32_t prng = 42;
|
||||
uint32_t prng_ = prng;
|
||||
for (lfs3_size_t i = 0;
|
||||
i < (WRAPAROUND*COUNT)
|
||||
/ (N*(SIZE/BLOCK_SIZE));
|
||||
i++) {
|
||||
prng = prng_;
|
||||
for (lfs3_size_t n = 0; n < N; n++) {
|
||||
char name[256];
|
||||
sprintf(name, "file%08d", n);
|
||||
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||
}
|
||||
|
||||
lfs3_file_t file;
|
||||
lfs3_file_open(&lfs3, &file, name,
|
||||
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_TRUNC) => 0;
|
||||
lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE;
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
// remount before?
|
||||
if (REMOUNT & 2) {
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
}
|
||||
|
||||
// now remove the gbmap
|
||||
lfs3_fs_rmgbmap(&lfs3) => 0;
|
||||
|
||||
// remount after?
|
||||
if (REMOUNT & 1) {
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
}
|
||||
|
||||
// we should no longer have a gbmap
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(!(fsinfo.flags & LFS3_I_GBMAP));
|
||||
|
||||
// create n files repeatedly until we're sure we've wrapped around
|
||||
// a few times
|
||||
for (lfs3_size_t i = 0;
|
||||
i < (WRAPAROUND*COUNT)
|
||||
/ (N*(SIZE/BLOCK_SIZE));
|
||||
i++) {
|
||||
prng = prng_;
|
||||
for (lfs3_size_t n = 0; n < N; n++) {
|
||||
char name[256];
|
||||
sprintf(name, "file%08d", n);
|
||||
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||
}
|
||||
|
||||
lfs3_file_t file;
|
||||
lfs3_file_open(&lfs3, &file, name,
|
||||
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_TRUNC) => 0;
|
||||
lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE;
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int remount = 0; remount < 2; remount++) {
|
||||
// remount?
|
||||
if (remount) {
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
}
|
||||
|
||||
// check that our file writes worked
|
||||
prng_ = prng;
|
||||
for (lfs3_size_t i = 0; i < N; i++) {
|
||||
// check with stat
|
||||
char name[256];
|
||||
sprintf(name, "file%08d", i);
|
||||
struct lfs3_info info;
|
||||
lfs3_stat(&lfs3, name, &info) => 0;
|
||||
assert(strcmp(info.name, name) == 0);
|
||||
assert(info.type == LFS3_TYPE_REG);
|
||||
assert(info.size == SIZE);
|
||||
|
||||
// try reading the file, note we reset prng above
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||
}
|
||||
|
||||
lfs3_file_t file;
|
||||
uint8_t rbuf[SIZE];
|
||||
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
||||
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE;
|
||||
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
'''
|
||||
|
||||
# test that we can make the gbmap and things still work
|
||||
[cases.test_gbmap_mkgbmap]
|
||||
ifndef = 'LFS3_YES_GBMAP'
|
||||
defines.COUNT = [
|
||||
'BLOCK_COUNT',
|
||||
'BLOCK_COUNT-1',
|
||||
'BLOCK_COUNT/2',
|
||||
'BLOCK_COUNT/4',
|
||||
'5',
|
||||
'3',
|
||||
]
|
||||
defines.SIZE = [
|
||||
'BLOCK_SIZE',
|
||||
'2*BLOCK_SIZE',
|
||||
'8*BLOCK_SIZE',
|
||||
]
|
||||
defines.N = ['5', 'BLOCK_COUNT/2']
|
||||
defines.WRAPAROUND = 3
|
||||
# REMOUNT=0 => don't remount
|
||||
# REMOUNT=1 => remount after
|
||||
# REMOUNT=2 => remount before
|
||||
# REMOUNT=3 => remount both after and before
|
||||
defines.REMOUNT = [0, 1, 2, 3]
|
||||
if = [
|
||||
'COUNT >= 3',
|
||||
'COUNT >= 2*N*SIZE/BLOCK_SIZE',
|
||||
]
|
||||
code = '''
|
||||
// test various block counts
|
||||
struct lfs3_cfg cfg = *CFG;
|
||||
cfg.block_count = COUNT;
|
||||
lfs3_t lfs3;
|
||||
// note the lack of gbmap flag
|
||||
lfs3_format(&lfs3, LFS3_F_RDWR, &cfg) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
|
||||
// check that we were formatted without the gbmap
|
||||
struct lfs3_fsinfo fsinfo;
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(!(fsinfo.flags & LFS3_I_GBMAP));
|
||||
|
||||
// create n files repeatedly until we're sure we've wrapped around
|
||||
// a few times
|
||||
uint32_t prng = 42;
|
||||
uint32_t prng_ = prng;
|
||||
for (lfs3_size_t i = 0;
|
||||
i < (WRAPAROUND*COUNT)
|
||||
/ (N*(SIZE/BLOCK_SIZE));
|
||||
i++) {
|
||||
prng = prng_;
|
||||
for (lfs3_size_t n = 0; n < N; n++) {
|
||||
char name[256];
|
||||
sprintf(name, "file%08d", n);
|
||||
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||
}
|
||||
|
||||
lfs3_file_t file;
|
||||
lfs3_file_open(&lfs3, &file, name,
|
||||
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_TRUNC) => 0;
|
||||
lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE;
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
// remount before?
|
||||
if (REMOUNT & 2) {
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
}
|
||||
|
||||
// now make the gbmap
|
||||
lfs3_fs_mkgbmap(&lfs3) => 0;
|
||||
|
||||
// remount after?
|
||||
if (REMOUNT & 1) {
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
}
|
||||
|
||||
// we should now have a gbmap
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(fsinfo.flags & LFS3_I_GBMAP);
|
||||
|
||||
// create n files repeatedly until we're sure we've wrapped around
|
||||
// a few times
|
||||
for (lfs3_size_t i = 0;
|
||||
i < (WRAPAROUND*COUNT)
|
||||
/ (N*(SIZE/BLOCK_SIZE));
|
||||
i++) {
|
||||
prng = prng_;
|
||||
for (lfs3_size_t n = 0; n < N; n++) {
|
||||
char name[256];
|
||||
sprintf(name, "file%08d", n);
|
||||
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||
}
|
||||
|
||||
lfs3_file_t file;
|
||||
lfs3_file_open(&lfs3, &file, name,
|
||||
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_TRUNC) => 0;
|
||||
lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE;
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int remount = 0; remount < 2; remount++) {
|
||||
// remount?
|
||||
if (remount) {
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
}
|
||||
|
||||
// check that our file writes worked
|
||||
prng_ = prng;
|
||||
for (lfs3_size_t i = 0; i < N; i++) {
|
||||
// check with stat
|
||||
char name[256];
|
||||
sprintf(name, "file%08d", i);
|
||||
struct lfs3_info info;
|
||||
lfs3_stat(&lfs3, name, &info) => 0;
|
||||
assert(strcmp(info.name, name) == 0);
|
||||
assert(info.type == LFS3_TYPE_REG);
|
||||
assert(info.size == SIZE);
|
||||
|
||||
// try reading the file, note we reset prng above
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||
}
|
||||
|
||||
lfs3_file_t file;
|
||||
uint8_t rbuf[SIZE];
|
||||
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
||||
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE;
|
||||
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
'''
|
||||
|
||||
# test that we can remove and then remake the gbmap and things still
|
||||
# work
|
||||
#
|
||||
# this leaves the disk with garbage gstate that mkgbmap needs to clean
|
||||
# up
|
||||
[cases.test_gbmap_rmmkgbmap]
|
||||
ifndef = 'LFS3_YES_GBMAP'
|
||||
defines.COUNT = [
|
||||
'BLOCK_COUNT',
|
||||
'BLOCK_COUNT-1',
|
||||
'BLOCK_COUNT/2',
|
||||
'BLOCK_COUNT/4',
|
||||
'5',
|
||||
'3',
|
||||
]
|
||||
defines.SIZE = [
|
||||
'BLOCK_SIZE',
|
||||
'2*BLOCK_SIZE',
|
||||
'8*BLOCK_SIZE',
|
||||
]
|
||||
defines.N = ['5', 'BLOCK_COUNT/2']
|
||||
defines.WRAPAROUND = 3
|
||||
# REMOUNT=0x1 => remount after
|
||||
# REMOUNT=0x2 => remount before make
|
||||
# REMOUNT=0x4 => remount after remove
|
||||
# REMOUNT=0x8 => remount before
|
||||
defines.REMOUNT = 'range(0x10)'
|
||||
if = [
|
||||
'COUNT >= 3',
|
||||
'COUNT >= 2*N*SIZE/BLOCK_SIZE',
|
||||
]
|
||||
code = '''
|
||||
// test various block counts
|
||||
struct lfs3_cfg cfg = *CFG;
|
||||
cfg.block_count = COUNT;
|
||||
lfs3_t lfs3;
|
||||
// note the gbmap flag
|
||||
lfs3_format(&lfs3, LFS3_F_RDWR | LFS3_F_GBMAP, &cfg) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
|
||||
// check that we were formatted with the gbmap
|
||||
struct lfs3_fsinfo fsinfo;
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(fsinfo.flags & LFS3_I_GBMAP);
|
||||
|
||||
// create n files repeatedly until we're sure we've wrapped around
|
||||
// a few times
|
||||
uint32_t prng = 42;
|
||||
uint32_t prng_ = prng;
|
||||
for (lfs3_size_t i = 0;
|
||||
i < (WRAPAROUND*COUNT)
|
||||
/ (N*(SIZE/BLOCK_SIZE));
|
||||
i++) {
|
||||
prng = prng_;
|
||||
for (lfs3_size_t n = 0; n < N; n++) {
|
||||
char name[256];
|
||||
sprintf(name, "file%08d", n);
|
||||
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||
}
|
||||
|
||||
lfs3_file_t file;
|
||||
lfs3_file_open(&lfs3, &file, name,
|
||||
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_TRUNC) => 0;
|
||||
lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE;
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
// remount before?
|
||||
if (REMOUNT & 8) {
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
}
|
||||
|
||||
// now remove the gbmap
|
||||
lfs3_fs_rmgbmap(&lfs3) => 0;
|
||||
|
||||
// remount after remove?
|
||||
if (REMOUNT & 4) {
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
}
|
||||
|
||||
// we should no longer have a gbmap
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(!(fsinfo.flags & LFS3_I_GBMAP));
|
||||
|
||||
// create n files repeatedly until we're sure we've wrapped around
|
||||
// a few times
|
||||
for (lfs3_size_t i = 0;
|
||||
i < (WRAPAROUND*COUNT)
|
||||
/ (N*(SIZE/BLOCK_SIZE));
|
||||
i++) {
|
||||
prng = prng_;
|
||||
for (lfs3_size_t n = 0; n < N; n++) {
|
||||
char name[256];
|
||||
sprintf(name, "file%08d", n);
|
||||
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||
}
|
||||
|
||||
lfs3_file_t file;
|
||||
lfs3_file_open(&lfs3, &file, name,
|
||||
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_TRUNC) => 0;
|
||||
lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE;
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
// remount before make?
|
||||
if (REMOUNT & 2) {
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
}
|
||||
|
||||
// now remake the gbmap
|
||||
lfs3_fs_mkgbmap(&lfs3) => 0;
|
||||
|
||||
// remount after?
|
||||
if (REMOUNT & 1) {
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
}
|
||||
|
||||
// we should now have a gbmap
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(fsinfo.flags & LFS3_I_GBMAP);
|
||||
|
||||
// create n files repeatedly until we're sure we've wrapped around
|
||||
// a few times
|
||||
for (lfs3_size_t i = 0;
|
||||
i < (WRAPAROUND*COUNT)
|
||||
/ (N*(SIZE/BLOCK_SIZE));
|
||||
i++) {
|
||||
prng = prng_;
|
||||
for (lfs3_size_t n = 0; n < N; n++) {
|
||||
char name[256];
|
||||
sprintf(name, "file%08d", n);
|
||||
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||
}
|
||||
|
||||
lfs3_file_t file;
|
||||
lfs3_file_open(&lfs3, &file, name,
|
||||
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_TRUNC) => 0;
|
||||
lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE;
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int remount = 0; remount < 2; remount++) {
|
||||
// remount?
|
||||
if (remount) {
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
}
|
||||
|
||||
// check that our file writes worked
|
||||
prng_ = prng;
|
||||
for (lfs3_size_t i = 0; i < N; i++) {
|
||||
// check with stat
|
||||
char name[256];
|
||||
sprintf(name, "file%08d", i);
|
||||
struct lfs3_info info;
|
||||
lfs3_stat(&lfs3, name, &info) => 0;
|
||||
assert(strcmp(info.name, name) == 0);
|
||||
assert(info.type == LFS3_TYPE_REG);
|
||||
assert(info.size == SIZE);
|
||||
|
||||
// try reading the file, note we reset prng above
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||
}
|
||||
|
||||
lfs3_file_t file;
|
||||
uint8_t rbuf[SIZE];
|
||||
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
||||
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE;
|
||||
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
'''
|
||||
|
||||
# test that we can make and then remove the gbmap and things still
|
||||
# work
|
||||
#
|
||||
# not exactly sure what this tests, but including for completeness
|
||||
[cases.test_gbmap_mkrmgbmap]
|
||||
ifndef = 'LFS3_YES_GBMAP'
|
||||
defines.COUNT = [
|
||||
'BLOCK_COUNT',
|
||||
'BLOCK_COUNT-1',
|
||||
'BLOCK_COUNT/2',
|
||||
'BLOCK_COUNT/4',
|
||||
'5',
|
||||
'3',
|
||||
]
|
||||
defines.SIZE = [
|
||||
'BLOCK_SIZE',
|
||||
'2*BLOCK_SIZE',
|
||||
'8*BLOCK_SIZE',
|
||||
]
|
||||
defines.N = ['5', 'BLOCK_COUNT/2']
|
||||
defines.WRAPAROUND = 3
|
||||
# REMOUNT=0x1 => remount after
|
||||
# REMOUNT=0x2 => remount before remove
|
||||
# REMOUNT=0x4 => remount after make
|
||||
# REMOUNT=0x8 => remount before
|
||||
defines.REMOUNT = 'range(0x10)'
|
||||
if = [
|
||||
'COUNT >= 3',
|
||||
'COUNT >= 2*N*SIZE/BLOCK_SIZE',
|
||||
]
|
||||
code = '''
|
||||
// test various block counts
|
||||
struct lfs3_cfg cfg = *CFG;
|
||||
cfg.block_count = COUNT;
|
||||
lfs3_t lfs3;
|
||||
// note the lack of gbmap flag
|
||||
lfs3_format(&lfs3, LFS3_F_RDWR, &cfg) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
|
||||
// check that we were formatted without the gbmap
|
||||
struct lfs3_fsinfo fsinfo;
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(!(fsinfo.flags & LFS3_I_GBMAP));
|
||||
|
||||
// create n files repeatedly until we're sure we've wrapped around
|
||||
// a few times
|
||||
uint32_t prng = 42;
|
||||
uint32_t prng_ = prng;
|
||||
for (lfs3_size_t i = 0;
|
||||
i < (WRAPAROUND*COUNT)
|
||||
/ (N*(SIZE/BLOCK_SIZE));
|
||||
i++) {
|
||||
prng = prng_;
|
||||
for (lfs3_size_t n = 0; n < N; n++) {
|
||||
char name[256];
|
||||
sprintf(name, "file%08d", n);
|
||||
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||
}
|
||||
|
||||
lfs3_file_t file;
|
||||
lfs3_file_open(&lfs3, &file, name,
|
||||
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_TRUNC) => 0;
|
||||
lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE;
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
// remount before?
|
||||
if (REMOUNT & 8) {
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
}
|
||||
|
||||
// now make the gbmap
|
||||
lfs3_fs_mkgbmap(&lfs3) => 0;
|
||||
|
||||
// remount after make?
|
||||
if (REMOUNT & 4) {
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
}
|
||||
|
||||
// we should now have a gbmap
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(fsinfo.flags & LFS3_I_GBMAP);
|
||||
|
||||
// create n files repeatedly until we're sure we've wrapped around
|
||||
// a few times
|
||||
for (lfs3_size_t i = 0;
|
||||
i < (WRAPAROUND*COUNT)
|
||||
/ (N*(SIZE/BLOCK_SIZE));
|
||||
i++) {
|
||||
prng = prng_;
|
||||
for (lfs3_size_t n = 0; n < N; n++) {
|
||||
char name[256];
|
||||
sprintf(name, "file%08d", n);
|
||||
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||
}
|
||||
|
||||
lfs3_file_t file;
|
||||
lfs3_file_open(&lfs3, &file, name,
|
||||
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_TRUNC) => 0;
|
||||
lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE;
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
// remount before remove?
|
||||
if (REMOUNT & 2) {
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
}
|
||||
|
||||
// now remove the gbmap
|
||||
lfs3_fs_rmgbmap(&lfs3) => 0;
|
||||
|
||||
// remount after?
|
||||
if (REMOUNT & 1) {
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
}
|
||||
|
||||
// we should no longer have a gbmap
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(!(fsinfo.flags & LFS3_I_GBMAP));
|
||||
|
||||
// create n files repeatedly until we're sure we've wrapped around
|
||||
// a few times
|
||||
for (lfs3_size_t i = 0;
|
||||
i < (WRAPAROUND*COUNT)
|
||||
/ (N*(SIZE/BLOCK_SIZE));
|
||||
i++) {
|
||||
prng = prng_;
|
||||
for (lfs3_size_t n = 0; n < N; n++) {
|
||||
char name[256];
|
||||
sprintf(name, "file%08d", n);
|
||||
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||
}
|
||||
|
||||
lfs3_file_t file;
|
||||
lfs3_file_open(&lfs3, &file, name,
|
||||
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_TRUNC) => 0;
|
||||
lfs3_file_write(&lfs3, &file, wbuf, SIZE) => SIZE;
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int remount = 0; remount < 2; remount++) {
|
||||
// remount?
|
||||
if (remount) {
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
lfs3_mount(&lfs3, LFS3_M_RDWR, &cfg) => 0;
|
||||
}
|
||||
|
||||
// check that our file writes worked
|
||||
prng_ = prng;
|
||||
for (lfs3_size_t i = 0; i < N; i++) {
|
||||
// check with stat
|
||||
char name[256];
|
||||
sprintf(name, "file%08d", i);
|
||||
struct lfs3_info info;
|
||||
lfs3_stat(&lfs3, name, &info) => 0;
|
||||
assert(strcmp(info.name, name) == 0);
|
||||
assert(info.type == LFS3_TYPE_REG);
|
||||
assert(info.size == SIZE);
|
||||
|
||||
// try reading the file, note we reset prng above
|
||||
uint8_t wbuf[SIZE];
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
wbuf[j] = 'a' + (TEST_PRNG(&prng_) % 26);
|
||||
}
|
||||
|
||||
lfs3_file_t file;
|
||||
uint8_t rbuf[SIZE];
|
||||
lfs3_file_open(&lfs3, &file, name, LFS3_O_RDONLY) => 0;
|
||||
lfs3_file_read(&lfs3, &file, rbuf, SIZE) => SIZE;
|
||||
assert(memcmp(rbuf, wbuf, SIZE) == 0);
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
}
|
||||
}
|
||||
|
||||
lfs3_unmount(&lfs3) => 0;
|
||||
'''
|
||||
|
||||
Reference in New Issue
Block a user