From f2e6b60f362fc128784af1adbe4de9f7d2cb1962 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 29 Apr 2025 12:32:01 -0500 Subject: [PATCH] Reworked grm encoding a bit This drops the leading count/mode byte, and instead uses mid=0 to terminate grms. This shaves off 1 bytes from grmdeltas. Previously, we needed the count/mode byte for a couple reasons: - We needed to know the number of grm entries somehow, and there wasn't always an obvious sentinel value. mid=-1, for example, is unrepresentable with our unsigned leb128 encoding. But now that development has settled, we can use mid=0.0 to figure out the end-of-queue. mid=0.0 should always map to the root bookmark, which doesn't make sense to delete, so it makes for a reasonable null terminator here. - It provided a route for future grm extensions, which could use the >2 count/mode encodings. But I think we can use additional grm tag encodings for this. There's only one gdelta tag so far, but the current plan for future gdelta tags is to carve out the bottom 2 bits for redund like we do with the struct tags: LFSR_TAG_GDELTA 0x01tt v--- ---1 -ttt ttrr LFSR_TAG_GRMDELTA 0x0100 v--- ---1 ---- ---- LFSR_TAG_GBMAPDELTA 0x0104 v--- ---1 ---- -1rr LFSR_TAG_GDDTREEDELTA 0x0108 v--- ---1 ---- 1-rr LFSR_TAG_GPTREEDELTA 0x010c v--- ---1 ---- 11rr ... Decoding is a bit more complicated for gstate, since we will need to xor those bits if mutable, but this avoids needing a full byte just for redund in every auxiliary tree. Long story short, we can leverage the lower 2 bits of the grm tag for future extensions using the same mechanism. This may seem like a lot of effort for only a handful of bytes, but keep in mind each gdelta lives in more-or-less every mdir in the filesystem. Also saves a bit of code/ctx: code stack ctx before: 35772 2368 640 after: 35768 (-0.0%) 2368 (+0.0%) 636 (-0.6%) --- lfs.c | 144 +++++++++++++++++++----------------- lfs.h | 10 +-- scripts/dbgbmap.py | 32 ++++---- scripts/dbgbmapd3.py | 32 ++++---- scripts/dbglfs.py | 32 ++++---- tests/test_stickynotes.toml | 16 ++-- tests/test_traversal.toml | 32 ++++---- 7 files changed, 145 insertions(+), 153 deletions(-) diff --git a/lfs.c b/lfs.c index bd5f62ff..f9dfbd84 100644 --- a/lfs.c +++ b/lfs.c @@ -7185,29 +7185,34 @@ static void lfsr_fs_mkdirty(lfs_t *lfs) { /// Global-state things /// // grm (global remove) things -static inline uint8_t lfsr_grm_count_(const lfsr_grm_t *grm) { - return (grm->mids[0] >= 0) + (grm->mids[1] >= 0); +static inline lfs_size_t lfsr_grm_count_(const lfsr_grm_t *grm) { + return (grm->queue[0] != 0) + (grm->queue[1] != 0); } -static inline uint8_t lfsr_grm_count(const lfs_t *lfs) { +static inline lfs_size_t lfsr_grm_count(const lfs_t *lfs) { return lfsr_grm_count_(&lfs->grm); } static inline void lfsr_grm_push(lfs_t *lfs, lfsr_smid_t mid) { - LFS_ASSERT(lfs->grm.mids[1] == -1); - lfs->grm.mids[1] = lfs->grm.mids[0]; - lfs->grm.mids[0] = mid; + // note mid=0.0 always maps to the root bookmark and should never + // be grmed + LFS_ASSERT(mid != 0); + LFS_ASSERT(lfs->grm.queue[1] == 0); + lfs->grm.queue[1] = lfs->grm.queue[0]; + lfs->grm.queue[0] = mid; } static inline lfsr_smid_t lfsr_grm_pop(lfs_t *lfs) { - lfsr_smid_t mid = lfs->grm.mids[0]; - lfs->grm.mids[0] = lfs->grm.mids[1]; - lfs->grm.mids[1] = -1; + lfsr_smid_t mid = lfs->grm.queue[0]; + lfs->grm.queue[0] = lfs->grm.queue[1]; + lfs->grm.queue[1] = 0; return mid; } static inline bool lfsr_grm_ismidrm(const lfs_t *lfs, lfsr_smid_t mid) { - return lfs->grm.mids[0] == mid || lfs->grm.mids[1] == mid; + return mid != 0 + && (lfs->grm.queue[0] == mid + || lfs->grm.queue[1] == mid); } #define LFSR_DATA_GRM(_grm, _buffer) \ @@ -7218,15 +7223,11 @@ static lfsr_data_t lfsr_data_fromgrm(const lfsr_grm_t *grm, // make sure to zero so we don't leak any info lfs_memset(buffer, 0, LFSR_GRM_DSIZE); - // first encode the number of grms, this can be 0, 1, or 2 and may - // be extended to a general purpose leb128 type field in the future - uint8_t mode = lfsr_grm_count_(grm); + // encode grms + lfs_size_t count = lfsr_grm_count_(grm); lfs_ssize_t d = 0; - buffer[d] = mode; - d += 1; - - for (uint8_t i = 0; i < mode; i++) { - lfs_ssize_t d_ = lfs_toleb128(grm->mids[i], &buffer[d], 5); + for (lfs_size_t i = 0; i < count; i++) { + lfs_ssize_t d_ = lfs_toleb128(grm->queue[i], &buffer[d], 5); if (d_ < 0) { LFS_UNREACHABLE(); } @@ -7242,28 +7243,26 @@ static inline lfsr_mid_t lfsr_mtree_weight(lfs_t *lfs); static int lfsr_data_readgrm(lfs_t *lfs, lfsr_data_t *data, lfsr_grm_t *grm) { // clear first - grm->mids[0] = -1; - grm->mids[1] = -1; + grm->queue[0] = 0; + grm->queue[1] = 0; - // first read the mode field - uint8_t mode; - lfs_ssize_t d = lfsr_data_read(lfs, data, &mode, 1); - if (d < 0) { - return d; - } - LFS_ASSERT(d == 1); - - // unknown mode? return an error, we may be able to mount read-only - if (mode > 2) { - return LFS_ERR_CORRUPT; - } - - for (uint8_t i = 0; i < mode; i++) { - int err = lfsr_data_readleb128(lfs, data, (lfsr_mid_t*)&grm->mids[i]); + // decode grms, these are terminated by either a null (mid=0) or the + // size of the grm buffer + for (lfs_size_t i = 0; i < 2; i++) { + lfsr_mid_t mid; + int err = lfsr_data_readleb128(lfs, data, &mid); if (err) { return err; } - LFS_ASSERT((lfsr_mid_t)grm->mids[i] < lfsr_mtree_weight(lfs)); + + // null grm? + if (!mid) { + break; + } + + // grm inside mtree? + LFS_ASSERT(mid < lfsr_mtree_weight(lfs)); + grm->queue[i] = mid; } return 0; @@ -7271,24 +7270,31 @@ static int lfsr_data_readgrm(lfs_t *lfs, lfsr_data_t *data, // some mdir-related gstate things we need + +// zero any pending gdeltas static void lfsr_fs_flushgdelta(lfs_t *lfs) { - // zero any pending gdeltas + // zero the gcksumdelta lfs->gcksum_d = 0; + // zero the grmdelta lfs_memset(lfs->grm_d, 0, LFSR_GRM_DSIZE); } +// commit any pending gdeltas static void lfsr_fs_commitgdelta(lfs_t *lfs) { - // commit any pending gdeltas + // keep track of the on-disk gcksum lfs->gcksum_p = lfs->gcksum; + // keep track of the on-disk grm lfsr_data_fromgrm(&lfs->grm, lfs->grm_p); } +// revert gstate to on-disk state static void lfsr_fs_revertgdelta(lfs_t *lfs) { - // revert gstate to on-disk state + // revert to the on-disk gcksum lfs->gcksum = lfs->gcksum_p; + // revert to the on-disk grm int err = lfsr_data_readgrm(lfs, &LFSR_DATA_BUF(lfs->grm_p, LFSR_GRM_DSIZE), &lfs->grm); @@ -8526,13 +8532,13 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, // adjust pending grms? } else { for (int j = 0; j < 2; j++) { - if (lfsr_mbid(lfs, lfs->grm.mids[j]) == lfsr_mbid(lfs, mid_) - && lfs->grm.mids[j] >= mid_) { + if (lfsr_mbid(lfs, lfs->grm.queue[j]) == lfsr_mbid(lfs, mid_) + && lfs->grm.queue[j] >= mid_) { // deleting a pending grm doesn't really make sense - LFS_ASSERT(lfs->grm.mids[j] >= mid_ - rattrs[i].weight); + LFS_ASSERT(lfs->grm.queue[j] >= mid_ - rattrs[i].weight); // adjust the grm - lfs->grm.mids[j] += rattrs[i].weight; + lfs->grm.queue[j] += rattrs[i].weight; } } } @@ -8825,16 +8831,16 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, // patch any pending grms for (int j = 0; j < 2; j++) { - if (lfsr_mbid(lfs, lfs->grm.mids[j]) + if (lfsr_mbid(lfs, lfs->grm.queue[j]) == lfsr_mbid(lfs, lfs_smax(mdir->mid, 0))) { if (mdelta > 0 - && lfsr_mrid(lfs, lfs->grm.mids[j]) + && lfsr_mrid(lfs, lfs->grm.queue[j]) >= (lfsr_srid_t)mdir_[0].rbyd.weight) { - lfs->grm.mids[j] + lfs->grm.queue[j] += (1 << lfs->mbits) - mdir_[0].rbyd.weight; } - } else if (lfs->grm.mids[j] > mdir->mid) { - lfs->grm.mids[j] += mdelta; + } else if (lfs->grm.queue[j] > mdir->mid) { + lfs->grm.queue[j] += mdelta; } } @@ -10286,7 +10292,7 @@ int lfsr_mkdir(lfs_t *lfs, const char *path) { if (err) { return err; } - LFS_ASSERT(lfs->grm.mids[0] == mdir.mid); + LFS_ASSERT(lfs->grm.queue[0] == mdir.mid); // committing our bookmark may have changed the mid of our metadata entry, // we need to look it up again, we can at least avoid the full path walk @@ -10644,7 +10650,7 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) { // update moved files with the new mdir } else if (lfsr_o_type(o->flags) == LFS_TYPE_REG - && o->mdir.mid == lfs->grm.mids[0]) { + && o->mdir.mid == lfs->grm.queue[0]) { o->mdir = new_mdir; // mark any removed dirs as zombied @@ -10662,8 +10668,8 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) { } if (((lfsr_dir_t*)o)->did == old_did - && o->mdir.mid >= lfs->grm.mids[0]) { - if (o->mdir.mid == lfs->grm.mids[0]) { + && o->mdir.mid >= lfs->grm.queue[0]) { + if (o->mdir.mid == lfs->grm.queue[0]) { o->mdir.mid += 1; } else { ((lfsr_dir_t*)o)->pos -= 1; @@ -10673,7 +10679,7 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) { // clobber entangled traversals } else if (lfsr_o_type(o->flags) == LFS_type_TRAVERSAL && ((exists && o->mdir.mid == new_mdir.mid) - || o->mdir.mid == lfs->grm.mids[0])) { + || o->mdir.mid == lfs->grm.queue[0])) { lfsr_traversal_clobber(lfs, (lfsr_traversal_t*)o); } } @@ -13486,8 +13492,8 @@ static int lfs_init(lfs_t *lfs, uint32_t flags, lfs->gcksum_p = 0; lfs->gcksum_d = 0; - lfs->grm.mids[0] = -1; - lfs->grm.mids[1] = -1; + lfs->grm.queue[0] = -1; + lfs->grm.queue[1] = -1; lfs_memset(lfs->grm_p, 0, LFSR_GRM_DSIZE); lfs_memset(lfs->grm_d, 0, LFSR_GRM_DSIZE); @@ -14019,14 +14025,14 @@ static int lfsr_mountinited(lfs_t *lfs) { // found pending grms? this should only happen if we lost power if (lfsr_grm_count(lfs) == 2) { LFS_INFO("Found pending grm %"PRId32".%"PRId32" %"PRId32".%"PRId32, - lfsr_dbgmbid(lfs, lfs->grm.mids[0]), - lfsr_dbgmrid(lfs, lfs->grm.mids[0]), - lfsr_dbgmbid(lfs, lfs->grm.mids[1]), - lfsr_dbgmrid(lfs, lfs->grm.mids[1])); + lfsr_dbgmbid(lfs, lfs->grm.queue[0]), + lfsr_dbgmrid(lfs, lfs->grm.queue[0]), + lfsr_dbgmbid(lfs, lfs->grm.queue[1]), + lfsr_dbgmrid(lfs, lfs->grm.queue[1])); } else if (lfsr_grm_count(lfs) == 1) { LFS_INFO("Found pending grm %"PRId32".%"PRId32, - lfsr_dbgmbid(lfs, lfs->grm.mids[0]), - lfsr_dbgmrid(lfs, lfs->grm.mids[0])); + lfsr_dbgmbid(lfs, lfs->grm.queue[0]), + lfsr_dbgmrid(lfs, lfs->grm.queue[0])); } return 0; @@ -14434,22 +14440,22 @@ lfs_ssize_t lfsr_fs_size(lfs_t *lfs) { static int lfsr_fs_fixgrm(lfs_t *lfs) { if (lfsr_grm_count(lfs) == 2) { LFS_INFO("Fixing grm %"PRId32".%"PRId32" %"PRId32".%"PRId32, - lfsr_dbgmbid(lfs, lfs->grm.mids[0]), - lfsr_dbgmrid(lfs, lfs->grm.mids[0]), - lfsr_dbgmbid(lfs, lfs->grm.mids[1]), - lfsr_dbgmrid(lfs, lfs->grm.mids[1])); + lfsr_dbgmbid(lfs, lfs->grm.queue[0]), + lfsr_dbgmrid(lfs, lfs->grm.queue[0]), + lfsr_dbgmbid(lfs, lfs->grm.queue[1]), + lfsr_dbgmrid(lfs, lfs->grm.queue[1])); } else if (lfsr_grm_count(lfs) == 1) { LFS_INFO("Fixing grm %"PRId32".%"PRId32, - lfsr_dbgmbid(lfs, lfs->grm.mids[0]), - lfsr_dbgmrid(lfs, lfs->grm.mids[0])); + lfsr_dbgmbid(lfs, lfs->grm.queue[0]), + lfsr_dbgmrid(lfs, lfs->grm.queue[0])); } while (lfsr_grm_count(lfs) > 0) { - LFS_ASSERT(lfs->grm.mids[0] != -1); + LFS_ASSERT(lfs->grm.queue[0] != -1); // find our mdir lfsr_mdir_t mdir; - int err = lfsr_mtree_lookup(lfs, lfs->grm.mids[0], + int err = lfsr_mtree_lookup(lfs, lfs->grm.queue[0], &mdir); if (err) { LFS_ASSERT(err != LFS_ERR_NOENT); diff --git a/lfs.h b/lfs.h index 0b28550b..4b62a202 100644 --- a/lfs.h +++ b/lfs.h @@ -812,18 +812,16 @@ typedef struct lfsr_traversal { //} lfs_gstate_t; // grm encoding: -// .---. mode: 1 leb128 1 byte -// |mod| mids: 2 leb128s <=2x5 bytes -// +- -+- -+- -+- -+- -. total: <=11 bytes -// ' mid x mod ' +// .- -+- -+- -+- -+- -. mids: 2 leb128s <=2x5 bytes +// ' mids ' total: <=10 bytes // + + // ' ' // '- -+- -+- -+- -+- -' // -#define LFSR_GRM_DSIZE (1+5+5) +#define LFSR_GRM_DSIZE (5+5) typedef struct lfsr_grm { - lfsr_smid_t mids[2]; + lfsr_smid_t queue[2]; } lfsr_grm_t; #ifdef LFS_CKPARITY diff --git a/scripts/dbgbmap.py b/scripts/dbgbmap.py index db415cce..adf3aab3 100755 --- a/scripts/dbgbmap.py +++ b/scripts/dbgbmap.py @@ -2726,26 +2726,22 @@ class Gstate: def __init__(self, mtree, tag, gdeltas): super().__init__(mtree, tag, gdeltas) + queue = [] d = 0 - count, d_ = fromleb128(self.data, d); d += d_ - rms = [] - if count <= 2: - for _ in range(count): - mid, d_ = fromleb128(self.data, d); d += d_ - mid = mtree.mid(mid) - # map mbids -> -1 if mroot-inlined - if mtree.mtree is None: - mid = mtree.mid(-1, mid.mrid) - rms.append(mid) - self.count = count - self.rms = rms + for _ in range(2): + mid, d_ = fromleb128(self.data, d); d += d_ + # a null mid (mid=0.0) terminates the grm queue + if not mid: + break + mid = mtree.mid(mid) + # map mbids -> -1 if mroot-inlined + if mtree.mtree is None: + mid = mtree.mid(-1, mid.mrid) + queue.append(mid) + self.queue = queue def repr(self): - return 'grm %s' % ( - 'none' if self.count == 0 - else ' '.join(mid.repr() for mid in self.rms) - if self.count <= 2 - else '0x%x %d' % (self.count, len(self.data))) + return 'grm [%s]' % ', '.join(mid.repr() for mid in self.queue) # keep track of known gstate _known = [g for g in Gstate.__subclasses__() if g.tag is not None] @@ -2961,7 +2957,7 @@ class Lfs: if not isinstance(mid, Mid): mid = self.mid(mid) - return mid in self.gstate.grm.rms + return mid in self.gstate.grm.queue # lookup operations def lookup(self, mid, mdir=None, *, diff --git a/scripts/dbgbmapd3.py b/scripts/dbgbmapd3.py index 54e2bcd3..7b18fbe7 100755 --- a/scripts/dbgbmapd3.py +++ b/scripts/dbgbmapd3.py @@ -2756,26 +2756,22 @@ class Gstate: def __init__(self, mtree, tag, gdeltas): super().__init__(mtree, tag, gdeltas) + queue = [] d = 0 - count, d_ = fromleb128(self.data, d); d += d_ - rms = [] - if count <= 2: - for _ in range(count): - mid, d_ = fromleb128(self.data, d); d += d_ - mid = mtree.mid(mid) - # map mbids -> -1 if mroot-inlined - if mtree.mtree is None: - mid = mtree.mid(-1, mid.mrid) - rms.append(mid) - self.count = count - self.rms = rms + for _ in range(2): + mid, d_ = fromleb128(self.data, d); d += d_ + # a null mid (mid=0.0) terminates the grm queue + if not mid: + break + mid = mtree.mid(mid) + # map mbids -> -1 if mroot-inlined + if mtree.mtree is None: + mid = mtree.mid(-1, mid.mrid) + queue.append(mid) + self.queue = queue def repr(self): - return 'grm %s' % ( - 'none' if self.count == 0 - else ' '.join(mid.repr() for mid in self.rms) - if self.count <= 2 - else '0x%x %d' % (self.count, len(self.data))) + return 'grm [%s]' % ', '.join(mid.repr() for mid in self.queue) # keep track of known gstate _known = [g for g in Gstate.__subclasses__() if g.tag is not None] @@ -2991,7 +2987,7 @@ class Lfs: if not isinstance(mid, Mid): mid = self.mid(mid) - return mid in self.gstate.grm.rms + return mid in self.gstate.grm.queue # lookup operations def lookup(self, mid, mdir=None, *, diff --git a/scripts/dbglfs.py b/scripts/dbglfs.py index f6ecc862..91ca6ce1 100755 --- a/scripts/dbglfs.py +++ b/scripts/dbglfs.py @@ -2683,26 +2683,22 @@ class Gstate: def __init__(self, mtree, tag, gdeltas): super().__init__(mtree, tag, gdeltas) + queue = [] d = 0 - count, d_ = fromleb128(self.data, d); d += d_ - rms = [] - if count <= 2: - for _ in range(count): - mid, d_ = fromleb128(self.data, d); d += d_ - mid = mtree.mid(mid) - # map mbids -> -1 if mroot-inlined - if mtree.mtree is None: - mid = mtree.mid(-1, mid.mrid) - rms.append(mid) - self.count = count - self.rms = rms + for _ in range(2): + mid, d_ = fromleb128(self.data, d); d += d_ + # a null mid (mid=0.0) terminates the grm queue + if not mid: + break + mid = mtree.mid(mid) + # map mbids -> -1 if mroot-inlined + if mtree.mtree is None: + mid = mtree.mid(-1, mid.mrid) + queue.append(mid) + self.queue = queue def repr(self): - return 'grm %s' % ( - 'none' if self.count == 0 - else ' '.join(mid.repr() for mid in self.rms) - if self.count <= 2 - else '0x%x %d' % (self.count, len(self.data))) + return 'grm [%s]' % ', '.join(mid.repr() for mid in self.queue) # keep track of known gstate _known = [g for g in Gstate.__subclasses__() if g.tag is not None] @@ -2918,7 +2914,7 @@ class Lfs: if not isinstance(mid, Mid): mid = self.mid(mid) - return mid in self.gstate.grm.rms + return mid in self.gstate.grm.queue # lookup operations def lookup(self, mid, mdir=None, *, diff --git a/tests/test_stickynotes.toml b/tests/test_stickynotes.toml index a80d7c45..edaf366b 100644 --- a/tests/test_stickynotes.toml +++ b/tests/test_stickynotes.toml @@ -7976,8 +7976,8 @@ code = ''' lfsr_fs_mkconsistent(&lfs) => 0; // we should have cleaned up all grms/orphans - assert(lfs.grm.mids[0] == -1); - assert(lfs.grm.mids[1] == -1); + assert(lfs.grm.queue[0] == 0); + assert(lfs.grm.queue[1] == 0); assert(!(lfs.flags & LFS_I_MKCONSISTENT)); struct lfs_fsinfo fsinfo; @@ -8112,8 +8112,8 @@ code = ''' lfsr_fs_mkconsistent(&lfs) => 0; // we should have cleaned up all grms/orphans - assert(lfs.grm.mids[0] == -1); - assert(lfs.grm.mids[1] == -1); + assert(lfs.grm.queue[0] == 0); + assert(lfs.grm.queue[1] == 0); assert(!(lfs.flags & LFS_I_MKCONSISTENT)); struct lfs_fsinfo fsinfo; @@ -8262,8 +8262,8 @@ code = ''' lfsr_fs_mkconsistent(&lfs) => 0; // we should have cleaned up all grms/orphans - assert(lfs.grm.mids[0] == -1); - assert(lfs.grm.mids[1] == -1); + assert(lfs.grm.queue[0] == 0); + assert(lfs.grm.queue[1] == 0); assert(!(lfs.flags & LFS_I_MKCONSISTENT)); struct lfs_fsinfo fsinfo; @@ -8418,8 +8418,8 @@ code = ''' lfsr_fs_mkconsistent(&lfs) => 0; // we should have cleaned up all grms/orphans - assert(lfs.grm.mids[0] == -1); - assert(lfs.grm.mids[1] == -1); + assert(lfs.grm.queue[0] == 0); + assert(lfs.grm.queue[1] == 0); assert(!(lfs.flags & LFS_I_MKCONSISTENT)); struct lfs_fsinfo fsinfo; diff --git a/tests/test_traversal.toml b/tests/test_traversal.toml index 27e43e5e..b6741dd8 100644 --- a/tests/test_traversal.toml +++ b/tests/test_traversal.toml @@ -6461,8 +6461,8 @@ code = ''' lfsr_traversal_close(&lfs, &t) => 0; // we should have cleaned up all grms/orphans - assert(lfs.grm.mids[0] == -1); - assert(lfs.grm.mids[1] == -1); + assert(lfs.grm.queue[0] == 0); + assert(lfs.grm.queue[1] == 0); assert(!(lfs.flags & LFS_I_MKCONSISTENT)); // which means there shouldn't be that many files left @@ -6603,8 +6603,8 @@ code = ''' lfsr_traversal_close(&lfs, &t) => 0; // we should be able to clean up grms - assert(lfs.grm.mids[0] == -1); - assert(lfs.grm.mids[1] == -1); + assert(lfs.grm.queue[0] == 0); + assert(lfs.grm.queue[1] == 0); // if we introduce actual orphans, me _must not_ clear the orphan flag if (ORPHANS >= 3) { assert(lfs.flags & LFS_I_MKCONSISTENT); @@ -6762,8 +6762,8 @@ code = ''' lfsr_traversal_close(&lfs, &t) => 0; // we should have cleaned up all grms/orphans - assert(lfs.grm.mids[0] == -1); - assert(lfs.grm.mids[1] == -1); + assert(lfs.grm.queue[0] == 0); + assert(lfs.grm.queue[1] == 0); assert(!(lfs.flags & LFS_I_MKCONSISTENT)); // which means there shouldn't be that many files left @@ -6920,8 +6920,8 @@ code = ''' lfsr_traversal_close(&lfs, &t) => 0; // we should have cleaned up all grms/orphans - assert(lfs.grm.mids[0] == -1); - assert(lfs.grm.mids[1] == -1); + assert(lfs.grm.queue[0] == 0); + assert(lfs.grm.queue[1] == 0); assert(!(lfs.flags & LFS_I_MKCONSISTENT)); // which means there shouldn't be that many files left @@ -7089,8 +7089,8 @@ code = ''' lfsr_traversal_close(&lfs, &t) => 0; // we should have cleaned up all grms/orphans - assert(lfs.grm.mids[0] == -1); - assert(lfs.grm.mids[1] == -1); + assert(lfs.grm.queue[0] == 0); + assert(lfs.grm.queue[1] == 0); assert(!(lfs.flags & LFS_I_MKCONSISTENT)); // which means there shouldn't be that many files left @@ -7256,8 +7256,8 @@ code = ''' lfsr_traversal_close(&lfs, &t) => 0; // we should have cleaned up all grms/orphans - assert(lfs.grm.mids[0] == -1); - assert(lfs.grm.mids[1] == -1); + assert(lfs.grm.queue[0] == 0); + assert(lfs.grm.queue[1] == 0); assert(!(lfs.flags & LFS_I_MKCONSISTENT)); // which means there shouldn't be that many files left @@ -7421,8 +7421,8 @@ code = ''' lfsr_traversal_read(&lfs, &t, &tinfo) => LFS_ERR_NOENT; // we should have cleaned up all grms/orphans - assert(lfs.grm.mids[0] == -1); - assert(lfs.grm.mids[1] == -1); + assert(lfs.grm.queue[0] == 0); + assert(lfs.grm.queue[1] == 0); assert(!(lfs.flags & LFS_I_MKCONSISTENT)); // which means there shouldn't be that many files left @@ -7614,8 +7614,8 @@ code = ''' lfsr_traversal_close(&lfs, &t) => 0; // we should be able to clean up grms - assert(lfs.grm.mids[0] == -1); - assert(lfs.grm.mids[1] == -1); + assert(lfs.grm.queue[0] == 0); + assert(lfs.grm.queue[1] == 0); // if we introduce actual orphans, me _must not_ clear the orphan flag if (ORPHANS >= 3) { assert(lfs.flags & LFS_I_MKCONSISTENT);