diff --git a/lfs3.c b/lfs3.c index 87ac2bae..6f2d7eb3 100644 --- a/lfs3.c +++ b/lfs3.c @@ -9783,6 +9783,13 @@ enum lfs3_tstate { LFS3_TSTATE_DONE = 8, }; +// tortoise for cycle detection +typedef struct lfs3_mtortoise { + lfs3_block_t blocks[2]; + lfs3_block_t dist; + uint8_t power; +} lfs3_mtortoise_t; + static void lfs3_trv_init(lfs3_trv_t *trv, uint32_t flags) { trv->b.h.flags = lfs3_o_typeflags(LFS3_type_TRV) | lfs3_t_tstateflags(LFS3_TSTATE_MROOTANCHOR) @@ -9792,11 +9799,15 @@ static void lfs3_trv_init(lfs3_trv_t *trv, uint32_t flags) { trv->b.h.mdir.r.blocks[0] = -1; trv->b.h.mdir.r.blocks[1] = -1; lfs3_bshrub_init(&trv->b); + // bit of a hack, but we reuse the shrub's leaf as a tortoise for + // cycle detection to save memory, see lfs3_mtree_traverse_ + lfs3_mtortoise_t *mtortoise = (lfs3_mtortoise_t*)&trv->b.shrub.leaf.r; + LFS3_ASSERT(sizeof(lfs3_mtortoise_t) <= sizeof(trv->b.shrub.leaf.r)); + mtortoise->blocks[0] = -1; + mtortoise->blocks[1] = -1; + mtortoise->dist = 0; + mtortoise->power = 0; trv->h = NULL; - trv->u.mtortoise.blocks[0] = -1; - trv->u.mtortoise.blocks[1] = -1; - trv->u.mtortoise.step = 0; - trv->u.mtortoise.power = 0; trv->gcksum = 0; } @@ -9859,22 +9870,26 @@ static lfs3_stag_t lfs3_mtree_traverse_(lfs3_t *lfs3, lfs3_trv_t *trv, // btree inner nodes require checksums of their pointers, // so creating a valid cycle is actually quite difficult // + // a bit of a hack, but we reuse the shrub's leaf as a + // tortoise to save memory + lfs3_mtortoise_t *mtortoise + = (lfs3_mtortoise_t*)&trv->b.shrub.leaf.r; if (lfs3_mptr_cmp( trv->b.h.mdir.r.blocks, - trv->u.mtortoise.blocks) == 0) { + mtortoise->blocks) == 0) { LFS3_ERROR("Cycle detected during mtree traversal " "0x{%"PRIx32",%"PRIx32"}", trv->b.h.mdir.r.blocks[0], trv->b.h.mdir.r.blocks[1]); return LFS3_ERR_CORRUPT; } - if (trv->u.mtortoise.step == (1U << trv->u.mtortoise.power)) { - trv->u.mtortoise.blocks[0] = trv->b.h.mdir.r.blocks[0]; - trv->u.mtortoise.blocks[1] = trv->b.h.mdir.r.blocks[1]; - trv->u.mtortoise.step = 0; - trv->u.mtortoise.power += 1; + if (mtortoise->dist == (1U << mtortoise->power)) { + mtortoise->blocks[0] = trv->b.h.mdir.r.blocks[0]; + mtortoise->blocks[1] = trv->b.h.mdir.r.blocks[1]; + mtortoise->dist = 0; + mtortoise->power += 1; } - trv->u.mtortoise.step += 1; + mtortoise->dist += 1; bptr_->d.u.buffer = (const uint8_t*)&trv->b.h.mdir; return LFS3_TAG_MDIR; @@ -9889,7 +9904,7 @@ static lfs3_stag_t lfs3_mtree_traverse_(lfs3_t *lfs3, lfs3_trv_t *trv, } // transition to traversing the mtree - trv->u.bid = -2; + trv->bid = -2; lfs3_t_settstate(&trv->b.h.flags, LFS3_TSTATE_MTREE); continue; @@ -9945,7 +9960,7 @@ static lfs3_stag_t lfs3_mtree_traverse_(lfs3_t *lfs3, lfs3_trv_t *trv, // here, lfs3_bshrub_fetch ignores these for us if (err != LFS3_ERR_NOENT) { // start traversing - trv->u.bid = -2; + trv->bid = -2; lfs3_t_settstate(&trv->b.h.flags, LFS3_TSTATE_BTREE); continue; @@ -9990,7 +10005,7 @@ static lfs3_stag_t lfs3_mtree_traverse_(lfs3_t *lfs3, lfs3_trv_t *trv, // transition to traversing the file const lfs3_file_t *file = (const lfs3_file_t*)trv->h; trv->b.shrub = file->b.shrub; - trv->u.bid = -2; + trv->bid = -2; lfs3_t_settstate(&trv->b.h.flags, LFS3_TSTATE_HBTREE); continue; #endif @@ -10002,8 +10017,8 @@ static lfs3_stag_t lfs3_mtree_traverse_(lfs3_t *lfs3, lfs3_trv_t *trv, case LFS3_TSTATE_BTREE:; case LFS3_TSTATE_HBTREE:; // traverse through our bshrub/btree - tag = lfs3_bshrub_traverse(lfs3, &trv->b, trv->u.bid+1, - &trv->u.bid, NULL, &data); + tag = lfs3_bshrub_traverse(lfs3, &trv->b, trv->bid+1, + &trv->bid, NULL, &data); if (tag < 0) { if (tag == LFS3_ERR_NOENT) { // clear the bshrub state diff --git a/lfs3.h b/lfs3.h index 3eed2892..881309fd 100644 --- a/lfs3.h +++ b/lfs3.h @@ -771,20 +771,12 @@ typedef struct lfs3_dir { // littlefs traversal type typedef struct lfs3_trv { // mdir/bshrub/btree state, this also includes our traversal - // state machine + // state machine and cycle detection state lfs3_bshrub_t b; // opened file state lfs3_handle_t *h; - union { - // cycle detection state, only valid when traversing the mroot chain - struct { - lfs3_block_t blocks[2]; - lfs3_block_t step; - uint8_t power; - } mtortoise; - // btree traversal state - lfs3_sbid_t bid; - } u; + // bshrub/btree traversal state + lfs3_sbid_t bid; // recalculate gcksum when traversing with ckmeta uint32_t gcksum;