mirror of
https://github.com/littlefs-project/littlefs.git
synced 2025-12-01 12:20:02 +00:00
trv: Greatly simplified filesystem traversal
The main idea here is to drop the flag-encoded tstate state machine, and
replace it with a matrix controlled by special mid + bid values:
-- mid ->
-5 -4 -3 -2 >=-1
bid -2 x x x --> mdir
v >=-1 x gbm gbm x --> bshrub/btree
'----|----|----|----|----> mroot anchor
'----|----|----|----> mroot chain + mtree
'----|----|----> gbmap (in-ram gbmap)
'----|----> gbmap_p (on-disk gbmap)
'----> file bshrubs/btrees
This was motivated by the observation that everything in our filesystem
can be modeled as mdir + bshrub/btree tuples, as long as some states are
noops. And we can cleanly encode these tuples in the unused negative
mid + bid ranges without needing an explicit state machine.
Well, that and the previous tstate state machine approach being an ugly
pile of switch cases and messy logic.
Note though that some mids may need to traverse multiple mdirs/bshrub/
btrees:
- The mroot chain + mtree (mid=-4) needs to traverse all mroots in the
mroot chain, and detect any cycles.
- File mdirs (mid>=-1) need to traverse both the on-disk bshrub/btree
and any opened file handles' bshrubs/btrees before moving onto the
next mid.
This grows O(n^2) because all file handles are in one big unsorted
linked-list, but as usual we don't care.
In addition to the greatly simplified traversal logic, the new state
matrix simplifies traversal clobbering: Setting bid=-2 always forces a
bshrub/btree refetch.
This comes at the cost of traversal _precision_, i.e. we can now revisit
previously visited bshrub/btree nodes. But I think this is well worth it
for more robust traversal clobbering. Traversal clobbering is delicate
and difficult to get right.
Besides, we can already revisit blocks due to CoW references, so what's
the harm in revisiting blocks when under mutation?
---
The simpler traversal logic leads to a nice amount of code savings
across the board:
code stack ctx
before: 36476 2304 660
after: 35940 (-1.5%) 2280 (-1.0%) 660 (+0.0%)
code stack ctx
gbmap before: 39524 2320 772
gbmap after: 38916 (-1.5%) 2296 (-1.0%) 772 (+0.0%)
code stack ctx
gc before: 36548 2304 804
gc after: 36012 (-1.5%) 2280 (-1.0%) 776 (-3.5%)
Note the ctx savings in LFS3_GC mode. Most of the stack/ctx savings
comes from the smaller lfs3_mtrv_t struct, which no longer needs to
stage bshrubs (we no longer care about bshrubs across mdir commit as a
part of the above clobbering simplifications):
before after
lfs3_mtrv_t: 128 100 (-21.9%)
lfs3_mgc_t: 128 100 (-21.9%)
lfs3_trv_t: 136 108 (-20.6%)
Unfortunately, the simpler clobbering means now any gc work needs the
block queue (i.e. lfs3_trv_t), solely so clobbering the block queue
doesn't clobber unallocated memory. Not great but hopefully fixable.
---
Some other notes:
- As a part of simplifying traversal clobbering, everything is triggered
by lfs3_alloc_ckpoint (via lfs3_trv_ckpoint_).
This may clobber traversals more than is strictly necessary, but
that's kinda the idea. Better safe than sorry.
And no more need to explicit lfs3_handle_clobber calls is nice.
- Opened file handle iteration is now tracked by the traversal handle's
position in the handle linked-list, instead of a separate handle
pointer. This means one less thing to disentangle and makes traversals
no longer a special case for things like lfs3_handle_close.
You may think this bumps traversals up to O(n^3) in-ram, but because
we only ever visit each unique handle + mid once, we can keep the
total O(n^2) if we're smart about linked-list updates!
- lfs3_mdir_commit needed to be tweaked to accept mids<=-1, instead of
just mid=-1 for the mroot. Unfortunately I don't know how much this
costs on its own.
- The reorganization of lfs3_mtrv_t means lfs3_mtortoise_t gets its own
struct again!
- No more tstate state machine also frees up a big chunk of the
traversal flag space, which was getting pretty cramped.
This commit is contained in:
27
lfs3.h
27
lfs3.h
@ -338,7 +338,6 @@ enum lfs3_btype {
|
||||
|
||||
// internally used flags, don't use these
|
||||
#define LFS3_t_TYPE 0xf0000000 // The traversal's type
|
||||
#define LFS3_t_TSTATE 0x000f0000 // The current traversal state
|
||||
#define LFS3_t_BTYPE 0x00f00000 // The current block type
|
||||
#define LFS3_t_ZOMBIE 0x08000000 // File has been removed
|
||||
#define LFS3_t_DIRTY 0x04000000 // Filesystem ckpointed outside traversal
|
||||
@ -858,14 +857,26 @@ typedef struct lfs3_btrv {
|
||||
lfs3_srid_t rid;
|
||||
} lfs3_btrv_t;
|
||||
|
||||
typedef struct lfs3_mtortoise {
|
||||
// this aligns with btrv.bid
|
||||
lfs3_sbid_t bid;
|
||||
lfs3_block_t blocks[2];
|
||||
lfs3_block_t dist;
|
||||
uint8_t nlog2;
|
||||
} lfs3_mtortoise_t;
|
||||
|
||||
typedef struct lfs3_mtrv {
|
||||
// mdir/bshrub/btree state, this also includes our traversal
|
||||
// state machine and cycle detection state
|
||||
lfs3_bshrub_t b;
|
||||
// opened file state
|
||||
lfs3_handle_t *h;
|
||||
// bshrub/btree traversal state
|
||||
lfs3_btrv_t btrv;
|
||||
// mtree traversal state, our position in then handle linked-list
|
||||
// is also used to keep track of what handles we've seen
|
||||
lfs3_handle_t h;
|
||||
// current bshrub/btree
|
||||
lfs3_btree_t b;
|
||||
union {
|
||||
// bshrub/btree traversal state
|
||||
lfs3_btrv_t btrv;
|
||||
// mtortoise for cycle detection
|
||||
lfs3_mtortoise_t mtortoise;
|
||||
} u;
|
||||
|
||||
// recalculate gcksum when traversing with ckmeta
|
||||
uint32_t gcksum;
|
||||
|
||||
@ -154,18 +154,6 @@ t_BOOKMARK = 0x40000000 # i^ Type = bookmark
|
||||
t_ORPHAN = 0x50000000 # i^ Type = orphan
|
||||
t_TRAVERSAL = 0x60000000 # i^ Type = traversal
|
||||
t_UNKNOWN = 0x70000000 # i^ Type = unknown
|
||||
t_TSTATE = 0x000f0000 # im The current traversal state
|
||||
t_MROOTANCHOR = 0x00000000 # i^ Tstate = mroot-anchor
|
||||
t_MROOTCHAIN = 0x00010000 # i^ Tstate = mroot-chain
|
||||
t_MTREE = 0x00020000 # i^ Tstate = mtree
|
||||
t_MDIRS = 0x00030000 # i^ Tstate = mtree-mdirs
|
||||
t_MDIR = 0x00040000 # i^ Tstate = mdir
|
||||
t_BTREE = 0x00050000 # i^ Tstate = btree
|
||||
t_HANDLES = 0x00060000 # i^ Tstate = open-mdirs
|
||||
t_HBTREE = 0x00070000 # i^ Tstate = open-btree
|
||||
t_GBMAP = 0x00080000 # i^ Tstate = gbmap
|
||||
t_GBMAP_P = 0x00090000 # i^ Tstate = gbmap_p
|
||||
t_DONE = 0x000a0000 # i^ Tstate = done
|
||||
t_BTYPE = 0x00f00000 # im The current block type
|
||||
t_MDIR = 0x00100000 # i^ Btype = mdir
|
||||
t_BTREE = 0x00200000 # i^ Btype = btree
|
||||
|
||||
@ -1025,7 +1025,7 @@ code = '''
|
||||
}
|
||||
|
||||
if (tinfo.btype == LFS3_BTYPE_BTREE
|
||||
&& lfs3_t_tstate(trv.gc.t.b.h.flags) != LFS3_TSTATE_GBMAP) {
|
||||
&& trv.gc.t.h.mdir.mid != LFS3_MID_GBMAP) {
|
||||
if (k == i) {
|
||||
// clobber this block
|
||||
printf("clobbering 0x%x\n", tinfo.block);
|
||||
@ -1125,7 +1125,7 @@ code = '''
|
||||
|
||||
if ((tinfo.btype == LFS3_BTYPE_BTREE
|
||||
|| tinfo.btype == LFS3_BTYPE_DATA)
|
||||
&& lfs3_t_tstate(trv.gc.t.b.h.flags) != LFS3_TSTATE_GBMAP) {
|
||||
&& trv.gc.t.h.mdir.mid != LFS3_MID_GBMAP) {
|
||||
if (k == i) {
|
||||
// clobber this block
|
||||
printf("clobbering 0x%x\n", tinfo.block);
|
||||
@ -1231,7 +1231,7 @@ code = '''
|
||||
}
|
||||
|
||||
if (tinfo.btype == LFS3_BTYPE_BTREE
|
||||
&& lfs3_t_tstate(trv.gc.t.b.h.flags) != LFS3_TSTATE_GBMAP) {
|
||||
&& trv.gc.t.h.mdir.mid != LFS3_MID_GBMAP) {
|
||||
// found an interesting block?
|
||||
if (k == i) {
|
||||
badblock = tinfo.block;
|
||||
@ -1382,7 +1382,7 @@ code = '''
|
||||
|
||||
if ((tinfo.btype == LFS3_BTYPE_BTREE
|
||||
|| tinfo.btype == LFS3_BTYPE_DATA)
|
||||
&& lfs3_t_tstate(trv.gc.t.b.h.flags) != LFS3_TSTATE_GBMAP) {
|
||||
&& trv.gc.t.h.mdir.mid != LFS3_MID_GBMAP) {
|
||||
// found an interesting block?
|
||||
if (k == i) {
|
||||
badblock = tinfo.block;
|
||||
|
||||
@ -57,7 +57,7 @@ code = '''
|
||||
struct lfs3_fsinfo fsinfo;
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(fsinfo.flags & LFS3_I_RELOOKAHEAD);
|
||||
assert(lfs3.handles != &lfs3.gc.gc.t.b.h);
|
||||
assert(lfs3.handles != &lfs3.gc.gc.t.h);
|
||||
|
||||
// run GC until we make progress
|
||||
for (lfs3_block_t i = 0;; i++) {
|
||||
@ -127,11 +127,11 @@ code = '''
|
||||
struct lfs3_fsinfo fsinfo;
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(fsinfo.flags & LFS3_I_RELOOKAHEAD);
|
||||
assert(lfs3.handles != &lfs3.gc.gc.t.b.h);
|
||||
assert(lfs3.handles != &lfs3.gc.gc.t.h);
|
||||
|
||||
// run GC one step
|
||||
lfs3_fs_gc(&lfs3) => 0;
|
||||
assert(lfs3.handles == &lfs3.gc.gc.t.b.h);
|
||||
assert(lfs3.handles == &lfs3.gc.gc.t.h);
|
||||
|
||||
// mutate the filesystem
|
||||
lfs3_file_open(&lfs3, &file, "spider",
|
||||
@ -143,7 +143,7 @@ code = '''
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
|
||||
// run GC until our traversal is done
|
||||
while (lfs3.handles == &lfs3.gc.gc.t.b.h) {
|
||||
while (lfs3.handles == &lfs3.gc.gc.t.h) {
|
||||
lfs3_fs_gc(&lfs3) => 0;
|
||||
}
|
||||
|
||||
@ -318,7 +318,7 @@ code = '''
|
||||
struct lfs3_fsinfo fsinfo;
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(fsinfo.flags & LFS3_I_REGBMAP);
|
||||
assert(lfs3.handles != &lfs3.gc.gc.t.b.h);
|
||||
assert(lfs3.handles != &lfs3.gc.gc.t.h);
|
||||
|
||||
// run GC until we make progress
|
||||
for (lfs3_block_t i = 0;; i++) {
|
||||
@ -391,11 +391,11 @@ code = '''
|
||||
struct lfs3_fsinfo fsinfo;
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(fsinfo.flags & LFS3_I_REGBMAP);
|
||||
assert(lfs3.handles != &lfs3.gc.gc.t.b.h);
|
||||
assert(lfs3.handles != &lfs3.gc.gc.t.h);
|
||||
|
||||
// run GC one step
|
||||
lfs3_fs_gc(&lfs3) => 0;
|
||||
assert(lfs3.handles == &lfs3.gc.gc.t.b.h);
|
||||
assert(lfs3.handles == &lfs3.gc.gc.t.h);
|
||||
|
||||
// mutate the filesystem
|
||||
lfs3_file_open(&lfs3, &file, "spider",
|
||||
@ -407,7 +407,7 @@ code = '''
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
|
||||
// run GC until our traversal is done
|
||||
while (lfs3.handles == &lfs3.gc.gc.t.b.h) {
|
||||
while (lfs3.handles == &lfs3.gc.gc.t.h) {
|
||||
lfs3_fs_gc(&lfs3) => 0;
|
||||
}
|
||||
|
||||
@ -592,7 +592,7 @@ code = '''
|
||||
struct lfs3_fsinfo fsinfo;
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(fsinfo.flags & LFS3_I_COMPACTMETA);
|
||||
assert(lfs3.handles != &lfs3.gc.gc.t.b.h);
|
||||
assert(lfs3.handles != &lfs3.gc.gc.t.h);
|
||||
|
||||
// run GC until we make progress
|
||||
for (lfs3_block_t i = 0;; i++) {
|
||||
@ -684,19 +684,19 @@ code = '''
|
||||
struct lfs3_fsinfo fsinfo;
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(fsinfo.flags & LFS3_I_COMPACTMETA);
|
||||
assert(lfs3.handles != &lfs3.gc.gc.t.b.h);
|
||||
assert(lfs3.handles != &lfs3.gc.gc.t.h);
|
||||
|
||||
// run GC one traversal + one step
|
||||
while (true) {
|
||||
lfs3_fs_gc(&lfs3) => 0;
|
||||
|
||||
// internal traversal done?
|
||||
if (lfs3.handles != &lfs3.gc.gc.t.b.h) {
|
||||
if (lfs3.handles != &lfs3.gc.gc.t.h) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
lfs3_fs_gc(&lfs3) => 0;
|
||||
assert(lfs3.handles == &lfs3.gc.gc.t.b.h);
|
||||
assert(lfs3.handles == &lfs3.gc.gc.t.h);
|
||||
|
||||
// mutate the filesystem
|
||||
lfs3_file_rewind(&lfs3, &file) => 0;
|
||||
@ -707,7 +707,7 @@ code = '''
|
||||
lfs3_file_sync(&lfs3, &file) => 0;
|
||||
|
||||
// run GC until our traversal is done (twice for compactmeta)
|
||||
while (lfs3.handles == &lfs3.gc.gc.t.b.h) {
|
||||
while (lfs3.handles == &lfs3.gc.gc.t.h) {
|
||||
lfs3_fs_gc(&lfs3) => 0;
|
||||
}
|
||||
|
||||
@ -811,7 +811,7 @@ code = '''
|
||||
struct lfs3_fsinfo fsinfo;
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(fsinfo.flags & LFS3_I_MKCONSISTENT);
|
||||
assert(lfs3.handles != &lfs3.gc.gc.t.b.h);
|
||||
assert(lfs3.handles != &lfs3.gc.gc.t.h);
|
||||
|
||||
// run GC until we make progress
|
||||
for (lfs3_block_t i = 0;; i++) {
|
||||
@ -917,7 +917,7 @@ code = '''
|
||||
lfs3_fs_stat(&lfs3, &fsinfo) => 0;
|
||||
assert(fsinfo.flags & LFS3_I_MKCONSISTENT);
|
||||
#ifdef LFS3_GC
|
||||
assert(lfs3.handles != &lfs3.gc.gc.t.b.h);
|
||||
assert(lfs3.handles != &lfs3.gc.gc.t.h);
|
||||
#endif
|
||||
|
||||
// call lfs3_fs_mkconsistent
|
||||
@ -1021,9 +1021,9 @@ code = '''
|
||||
}
|
||||
|
||||
// run GC one step
|
||||
assert(lfs3.handles != &lfs3.gc.gc.t.b.h);
|
||||
assert(lfs3.handles != &lfs3.gc.gc.t.h);
|
||||
lfs3_fs_gc(&lfs3) => 0;
|
||||
assert(lfs3.handles == &lfs3.gc.gc.t.b.h);
|
||||
assert(lfs3.handles == &lfs3.gc.gc.t.h);
|
||||
|
||||
// create the rest of the orphans after GC has started
|
||||
for (lfs3_size_t i = 0; i < ORPHANS; i++) {
|
||||
@ -1045,7 +1045,7 @@ code = '''
|
||||
assert(fsinfo.flags & LFS3_I_MKCONSISTENT);
|
||||
|
||||
// run GC until our traversal is done
|
||||
while (lfs3.handles == &lfs3.gc.gc.t.b.h) {
|
||||
while (lfs3.handles == &lfs3.gc.gc.t.h) {
|
||||
lfs3_fs_gc(&lfs3) => 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1882,12 +1882,12 @@ code = '''
|
||||
lfs3_file_open(&lfs3, &file, "spider",
|
||||
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
} else {
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
assert(tinfo.block == 0 || tinfo.block == 1);
|
||||
}
|
||||
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
assert(tinfo.block == 0 || tinfo.block == 1);
|
||||
|
||||
if (WHEN == 2) {
|
||||
lfs3_file_t file;
|
||||
lfs3_file_open(&lfs3, &file, "spider",
|
||||
@ -1948,9 +1948,6 @@ code = '''
|
||||
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
assert(tinfo.block == 0 || tinfo.block == 1);
|
||||
// traverse gbmap
|
||||
if (GBMAP) {
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
@ -2034,12 +2031,12 @@ code = '''
|
||||
|
||||
if (WHEN == 1) {
|
||||
lfs3_mkdir(&lfs3, "spider") => 0;
|
||||
} else {
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
assert(tinfo.block == 0 || tinfo.block == 1);
|
||||
}
|
||||
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
assert(tinfo.block == 0 || tinfo.block == 1);
|
||||
|
||||
if (WHEN == 2) {
|
||||
lfs3_mkdir(&lfs3, "spider") => 0;
|
||||
}
|
||||
@ -2104,12 +2101,12 @@ code = '''
|
||||
|
||||
if (WHEN == 1) {
|
||||
lfs3_remove(&lfs3, "spider") => 0;
|
||||
} else {
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
assert(tinfo.block == 0 || tinfo.block == 1);
|
||||
}
|
||||
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
assert(tinfo.block == 0 || tinfo.block == 1);
|
||||
|
||||
if (WHEN == 2) {
|
||||
lfs3_remove(&lfs3, "spider") => 0;
|
||||
}
|
||||
@ -2174,11 +2171,12 @@ code = '''
|
||||
|
||||
if (WHEN == 1) {
|
||||
lfs3_rename(&lfs3, "spider", "scorpion") => 0;
|
||||
} else {
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
assert(tinfo.block == 0 || tinfo.block == 1);
|
||||
}
|
||||
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
assert(tinfo.block == 0 || tinfo.block == 1);
|
||||
// traverse gbmap
|
||||
if (GBMAP) {
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
@ -2188,6 +2186,13 @@ code = '''
|
||||
|
||||
if (WHEN == 2) {
|
||||
lfs3_rename(&lfs3, "spider", "scorpion") => 0;
|
||||
|
||||
// traverse gbmap again
|
||||
if (GBMAP) {
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
assert(tinfo.block == 2);
|
||||
}
|
||||
}
|
||||
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => LFS3_ERR_NOENT;
|
||||
@ -2248,7 +2253,8 @@ code = '''
|
||||
| ((CKMETA) ? LFS3_T_CKMETA : 0)
|
||||
| ((CKDATA) ? LFS3_T_CKDATA : 0)) => 0;
|
||||
|
||||
while (true) {
|
||||
// mutating traversals may never terminate, so stop at some point
|
||||
for (lfs3_size_t i = 0; i < 4*BLOCK_COUNT; i++) {
|
||||
// rewrite the file every step of the traversal
|
||||
lfs3_file_open(&lfs3, &file, "spider",
|
||||
LFS3_O_WRONLY | LFS3_O_TRUNC) => 0;
|
||||
@ -2337,7 +2343,8 @@ code = '''
|
||||
| ((CKMETA) ? LFS3_T_CKMETA : 0)
|
||||
| ((CKDATA) ? LFS3_T_CKDATA : 0)) => 0;
|
||||
|
||||
while (true) {
|
||||
// mutating traversals may never terminate, so stop at some point
|
||||
for (lfs3_size_t i = 0; i < 4*BLOCK_COUNT; i++) {
|
||||
// rewrite the file every step of the traversal
|
||||
lfs3_file_rewind(&lfs3, &file) => 0;
|
||||
for (lfs3_size_t j = 0; j < SIZE; j++) {
|
||||
@ -2572,6 +2579,14 @@ code = '''
|
||||
lfs3_file_write(&lfs3, &file, wbuf1, SIZE) => SIZE;
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
|
||||
// traverse btree
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
// traverse btree
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
@ -2682,6 +2697,11 @@ code = '''
|
||||
lfs3_file_write(&lfs3, &file, wbuf1, SIZE) => SIZE;
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
@ -2891,6 +2911,14 @@ code = '''
|
||||
lfs3_file_write(&lfs3, &file1, wbuf1, SIZE) => SIZE;
|
||||
lfs3_file_flush(&lfs3, &file1) => 0;
|
||||
|
||||
// traverse btree
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
// traverse btree
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
@ -3003,6 +3031,11 @@ code = '''
|
||||
lfs3_file_write(&lfs3, &file1, wbuf1, SIZE) => SIZE;
|
||||
lfs3_file_flush(&lfs3, &file1) => 0;
|
||||
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
@ -3108,6 +3141,15 @@ code = '''
|
||||
}
|
||||
lfs3_file_close(&lfs3, &file1) => 0;
|
||||
|
||||
// if not desync, traversal rewinds to mdir
|
||||
if (!DESYNC) {
|
||||
// traverse gbmap again
|
||||
if (GBMAP) {
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
assert(tinfo.block == 2);
|
||||
}
|
||||
}
|
||||
// we should be at end of traversal now
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => LFS3_ERR_NOENT;
|
||||
lfs3_trv_close(&lfs3, &trv) => 0;
|
||||
@ -3222,6 +3264,18 @@ code = '''
|
||||
}
|
||||
lfs3_file_close(&lfs3, &file1) => 0;
|
||||
|
||||
// if not desync, traversal rewinds to mdir
|
||||
if (!DESYNC) {
|
||||
// traverse btree
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
// traverse one data block
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
}
|
||||
// traverse another data block
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
// traverse btree
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
@ -3341,6 +3395,15 @@ code = '''
|
||||
}
|
||||
lfs3_file_close(&lfs3, &file1) => 0;
|
||||
|
||||
// if not desync, traversal rewinds to mdir
|
||||
if (!DESYNC) {
|
||||
// traverse one data block
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
}
|
||||
// traverse another data block
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
@ -3676,6 +3739,11 @@ code = '''
|
||||
// rename one file over another
|
||||
lfs3_rename(&lfs3, "tarantula", "spider") => 0;
|
||||
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
@ -3773,6 +3841,12 @@ code = '''
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// traverse gbmap
|
||||
if (GBMAP) {
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
assert(tinfo.block == 2);
|
||||
}
|
||||
// traverse mdir
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
@ -3904,7 +3978,9 @@ code = '''
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// traverse another data block
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
// traverse two data blocks
|
||||
@ -3912,7 +3988,7 @@ code = '''
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
// traverse mdir
|
||||
// traverse an mdir
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
@ -4043,7 +4119,9 @@ code = '''
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// traverse another data block
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
// traverse two data blocks
|
||||
@ -4146,6 +4224,12 @@ code = '''
|
||||
lfs3_remove(&lfs3, "uloborus") => 0;
|
||||
}
|
||||
|
||||
// traverse gbmap
|
||||
if (GBMAP) {
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
assert(tinfo.block == 2);
|
||||
}
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
@ -4258,7 +4342,9 @@ code = '''
|
||||
lfs3_remove(&lfs3, "uloborus") => 0;
|
||||
}
|
||||
|
||||
// traverse another data block
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
// traverse two data blocks
|
||||
@ -4370,6 +4456,17 @@ code = '''
|
||||
// still traverse inlined mroots, so if this breaks in the future
|
||||
// I wouldn't worry too much about it
|
||||
//
|
||||
// traverse an mdir
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
// traverse gbmap
|
||||
if (GBMAP) {
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
assert(tinfo.block == 2);
|
||||
}
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
@ -4496,7 +4593,9 @@ code = '''
|
||||
lfs3_remove(&lfs3, "uloborus") => 0;
|
||||
}
|
||||
|
||||
// traverse another data block
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
// traverse two data blocks
|
||||
@ -4635,6 +4734,15 @@ code = '''
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// traverse mtree
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
// traverse gbmap
|
||||
if (GBMAP) {
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
assert(tinfo.block == 2);
|
||||
}
|
||||
// traverse mdir
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
@ -4846,7 +4954,9 @@ code = '''
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// traverse another data block
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
// traverse mdir
|
||||
@ -5044,7 +5154,9 @@ code = '''
|
||||
lfs3_file_close(&lfs3, &file) => 0;
|
||||
i += 1;
|
||||
}
|
||||
// traverse another data block
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
// traverse mdir
|
||||
@ -5201,6 +5313,15 @@ code = '''
|
||||
lfs3_remove(&lfs3, "vulsor") => 0;
|
||||
}
|
||||
|
||||
// traverse mtree
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
// traverse gbmap
|
||||
if (GBMAP) {
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
assert(tinfo.block == 2);
|
||||
}
|
||||
// traverse mdir
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
@ -5410,7 +5531,9 @@ code = '''
|
||||
lfs3_remove(&lfs3, "vulsor") => 0;
|
||||
}
|
||||
|
||||
// traverse another data block
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
// traverse two data blocks
|
||||
@ -5578,6 +5701,20 @@ code = '''
|
||||
lfs3_remove(&lfs3, "vulsor") => 0;
|
||||
}
|
||||
|
||||
// traverse mdir
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
// traverse mtree
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
// traverse gbmap
|
||||
if (GBMAP) {
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
assert(tinfo.block == 2);
|
||||
}
|
||||
// traverse mdir
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
@ -5797,7 +5934,9 @@ code = '''
|
||||
lfs3_remove(&lfs3, "vulsor") => 0;
|
||||
}
|
||||
|
||||
// traverse another data block
|
||||
// traverse two data blocks
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_DATA);
|
||||
// traverse two data blocks
|
||||
@ -7193,10 +7332,12 @@ code = '''
|
||||
|
||||
// keep traversing
|
||||
if (ORPHANS <= 3) {
|
||||
// traverse mroot
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
assert(tinfo.block == 0 || tinfo.block == 1);
|
||||
if (ORPHANS == 0) {
|
||||
// traverse mroot
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
assert(tinfo.block == 0 || tinfo.block == 1);
|
||||
}
|
||||
// traverse gbmap
|
||||
if (GBMAP) {
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
@ -7204,6 +7345,12 @@ code = '''
|
||||
assert(tinfo.block == 2);
|
||||
}
|
||||
} else {
|
||||
// traverse gbmap
|
||||
if (GBMAP) {
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
assert(tinfo.block == 2);
|
||||
}
|
||||
// traverse mdirs
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
@ -8350,10 +8497,12 @@ code = '''
|
||||
|
||||
// keep traversing
|
||||
if (ORPHANS <= 3) {
|
||||
// traverse mroot
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
assert(tinfo.block == 0 || tinfo.block == 1);
|
||||
if (ORPHANS == 0) {
|
||||
// traverse mroot
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
assert(tinfo.block == 0 || tinfo.block == 1);
|
||||
}
|
||||
// traverse gbmap
|
||||
if (GBMAP) {
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
@ -8361,6 +8510,12 @@ code = '''
|
||||
assert(tinfo.block == 2);
|
||||
}
|
||||
} else {
|
||||
// traverse gbmap
|
||||
if (GBMAP) {
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_BTREE);
|
||||
assert(tinfo.block == 2);
|
||||
}
|
||||
// traverse mdirs
|
||||
lfs3_trv_read(&lfs3, &trv, &tinfo) => 0;
|
||||
assert(tinfo.btype == LFS3_BTYPE_MDIR);
|
||||
|
||||
Reference in New Issue
Block a user