Adopted rid-bound-dependent compressed mids.

This adopts a previously discarded idea for compressed mids with a few
tweaks to avoiding decoding the bid/rid portions as much as possible.

The idea of compressed mids is to shove both the mid bid and mid rid
into a single integer, saving RAM and potentially helping filesystem
integration where a unique per-file integer is useful.

Unfortunately this has proven tricky. littlefs fundamentally needs two
ids, one "bid" to lookup which mdir our entry resides on, and one "rid"
to lookup the entry in the mdir. It's tempting to use two half-sized
integers (16-bit for example), but this risks surprising limitations
around the number of files when blocks are either really large or
really small.

Optimally, we'd limit the number of bits reserved for the rid to the
upper bound of number of rids that can fit in a single mdir. This would
allows for more bids when the block size is small, and more rids when
the block size is large. This should roughly approximate the limits of
a per-file integer.

With a bit of math we can estimate the upper bound to be <=block_size/16
with our current compaction strategy.

This idea was previously discarded due to the overhead of extracting the
bids/rids when we need them, but the RAM savings and file-to-integer
mapping is too useful to give up. When it became clear half-width
integers wasn't really going to work, compressed mids became the new
plan:

  0bbbbbbb bbbbbbbb bbbbbbbb rrrrrrrr
  ^'-----------+-----------' '---+--'
  '------------|-----------------|---- sign-bit, reserved for driver
               |                 '---- nlog2(bs/16) bits for rid
               |                       (8-bits for 4KiB blocks)
               '---------------------- remaining bits for bid
                                       (23-bits for 4KiB blocks)

To reduce the overhead of encoding/decode bids/rids a few extra features
were added to the internal mdir APIs:

1. The mtree has been changed to store mids directly. Giving each mdir
   the upper bound as a weight. This allows direct lookup of mids
   without any sort of bid decoding, though does bake the upper bound
   estimate into the metadata of the filesystem, which isn't the
   cleanest design, but if it works it works.

   On the plus side, with this upper bound baked in to the filesystems,
   GRMs can be encoded in a single leb128, which is nice. This may have
   other savings if we ever store mids anywhere else in the filesystem.

2. rids are now mid relative in lfsr_mdir_lookup when non-negative. This
   is implemented with a simple condition that is hopefully optimized
   out when inlined, though there may be some room for improvement here.

3. rids are now mid relative in lfsr_mdir_commit. This was a bit tricky,
   but we can leverage the existing mechanisms for bid-relative rids
   used in the btree implementation.

The above changes make it so you can pass the mid around directly for
most of the mdir functions, hopefully reducing the mid decoding
overhead. This savings should only grow as more high-level filesystem
APIs are added.

Here is the resulting code/RAM changes for this entire change (from
before we adopted the mroot bit):

            code          stack          structs
  before:  20590           1784              908
  after:   20890 (+1.4%)   1744 (-2.3%)      864 (-5.1%)
This commit is contained in:
Christopher Haster
2023-08-30 14:56:54 -05:00
parent 2ea569c746
commit a9b81820b0
4 changed files with 640 additions and 650 deletions
+198 -202
View File
@@ -1548,20 +1548,9 @@ static inline lfs_ssize_t lfsr_mbidmask(lfs_t *lfs) {
return ~lfsr_mridmask(lfs); return ~lfsr_mridmask(lfs);
} }
#define LFSR_MID(_bid, _rid) ((lfsr_mid_t){.bid=_bid, .rid=_rid})
static inline int lfsr_mid_cmp(lfsr_mid_t a, lfsr_mid_t b) {
if (a.bid != b.bid) {
return a.bid - b.bid;
}
return a.rid - b.rid;
}
// we use the root's bookmark at 0.0 to represent root // we use the root's bookmark at 0.0 to represent root
// TODO does this not catch -0.0? static inline bool lfsr_mid_isroot(lfs_ssize_t mid) {
static inline bool lfsr_mid_isroot(lfsr_mid_t mid) { return mid == 0;
return lfsr_mid_cmp(mid, LFSR_MID(0, 0)) == 0;
} }
static inline bool lfsr_mdir_isroot(const lfsr_mdir_t *mdir) { static inline bool lfsr_mdir_isroot(const lfsr_mdir_t *mdir) {
@@ -1621,22 +1610,22 @@ static int lfsr_gdelta_xor(lfs_t *lfs,
// GRM (global remove) things // GRM (global remove) things
static inline bool lfsr_grm_hasrm(const lfsr_grm_t *grm) { static inline bool lfsr_grm_hasrm(const lfsr_grm_t *grm) {
return grm->rms[0].bid != -1; return grm->rms[0] != -1;
} }
static inline uint8_t lfsr_grm_count(const lfsr_grm_t *grm) { static inline uint8_t lfsr_grm_count(const lfsr_grm_t *grm) {
return (grm->rms[0].bid != -1) + (grm->rms[1].bid != -1); return (grm->rms[0] != -1) + (grm->rms[1] != -1);
} }
static inline void lfsr_grm_pushrm(lfsr_grm_t *grm, lfsr_mid_t mid) { static inline void lfsr_grm_pushrm(lfsr_grm_t *grm, lfs_ssize_t mid) {
LFS_ASSERT(grm->rms[1].bid == -1); LFS_ASSERT(grm->rms[1] == -1);
grm->rms[1] = grm->rms[0]; grm->rms[1] = grm->rms[0];
grm->rms[0] = mid; grm->rms[0] = mid;
} }
static inline void lfsr_grm_poprm(lfsr_grm_t *grm) { static inline void lfsr_grm_poprm(lfsr_grm_t *grm) {
grm->rms[0] = grm->rms[1]; grm->rms[0] = grm->rms[1];
grm->rms[1] = LFSR_MID(-1, -1); grm->rms[1] = -1;
} }
static int lfsr_grm_todisk(lfs_t *lfs, const lfsr_grm_t *grm, static int lfsr_grm_todisk(lfs_t *lfs, const lfsr_grm_t *grm,
@@ -1654,13 +1643,7 @@ static int lfsr_grm_todisk(lfs_t *lfs, const lfsr_grm_t *grm,
d += 1; d += 1;
for (uint8_t i = 0; i < count; i++) { for (uint8_t i = 0; i < count; i++) {
lfs_ssize_t d_ = lfs_toleb128(grm->rms[i].bid, &buffer[d], 5); lfs_ssize_t d_ = lfs_toleb128(grm->rms[i], &buffer[d], 5);
if (d_ < 0) {
return d_;
}
d += d_;
d_ = lfs_toleb128(grm->rms[i].rid, &buffer[d], 5);
if (d_ < 0) { if (d_ < 0) {
return d_; return d_;
} }
@@ -1676,6 +1659,10 @@ static inline lfs_size_t lfsr_mtree_weight(lfs_t *lfs);
static int lfsr_data_readgrm(lfs_t *lfs, lfsr_data_t *data, static int lfsr_data_readgrm(lfs_t *lfs, lfsr_data_t *data,
lfsr_grm_t *grm) { lfsr_grm_t *grm) {
// clear first
grm->rms[0] = -1;
grm->rms[1] = -1;
// get the count from the first byte // get the count from the first byte
uint8_t count; uint8_t count;
lfs_ssize_t d = lfsr_data_read(lfs, data, &count, 1); lfs_ssize_t d = lfsr_data_read(lfs, data, &count, 1);
@@ -1683,27 +1670,15 @@ static int lfsr_data_readgrm(lfs_t *lfs, lfsr_data_t *data,
return d; return d;
} }
// clear first
grm->rms[0] = LFSR_MID(-1, -1);
grm->rms[1] = LFSR_MID(-1, -1);
LFS_ASSERT(count <= 2); LFS_ASSERT(count <= 2);
for (uint8_t i = 0; i < count; i++) { for (uint8_t i = 0; i < count; i++) {
lfs_ssize_t bid; int err = lfsr_data_readleb128(lfs, data, &grm->rms[i]);
int err = lfsr_data_readleb128(lfs, data, &bid);
if (err) { if (err) {
return err; return err;
} }
lfs_ssize_t rid; LFS_ASSERT(grm->rms[i]
err = lfsr_data_readleb128(lfs, data, &rid); < lfs_smax32(lfsr_mtree_weight(lfs), lfsr_mbidweight(lfs)));
if (err) {
return err;
}
// adjust mid if mtree is inlined
LFS_ASSERT(bid < lfs_smax32(lfsr_mtree_weight(lfs), 1));
grm->rms[i] = LFSR_MID(bid, rid);
} }
return 0; return 0;
@@ -2890,13 +2865,17 @@ static int lfsr_rbyd_appendattrs(lfs_t *lfs, lfsr_rbyd_t *rbyd,
continue; continue;
} }
// calculate adjusted rid
lfs_ssize_t rid = (attrs[i].rid == -1
? -1
: (lfs_ssize_t)(attrs[i].rid - bid));
// don't write tags outside of the requested range // don't write tags outside of the requested range
if (lfs_smax32(attrs[i].rid - bid, -1) >= start_rid if (rid >= start_rid
// note the use of rid+1 and unsigned comparison here to // note the use of rid+1 and unsigned comparison here to
// treat end_rid=-1 as "unbounded" in such a way that rid=-1 // treat end_rid=-1 as "unbounded" in such a way that rid=-1
// is still included // is still included
&& (lfs_size_t)lfs_smax32(attrs[i].rid - bid, -1) + 1 && (lfs_size_t)(rid + 1) <= (lfs_size_t)end_rid) {
<= (lfs_size_t)end_rid) {
// this is a bit of a hack, but ignore any gstate tags here, // this is a bit of a hack, but ignore any gstate tags here,
// these need to be handled specially by upper-layers // these need to be handled specially by upper-layers
if (lfsr_tag_suptype(attrs[i].tag) == LFSR_TAG_GSTATE) { if (lfsr_tag_suptype(attrs[i].tag) == LFSR_TAG_GSTATE) {
@@ -2912,23 +2891,22 @@ static int lfsr_rbyd_appendattrs(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// skip the name tag, this is always replaced by upper layers // skip the name tag, this is always replaced by upper layers
lfsr_tag_t tag = LFSR_TAG_NAME + 0xff; lfsr_tag_t tag = LFSR_TAG_NAME + 0xff;
while (true) { while (true) {
lfs_ssize_t rid; lfs_ssize_t rid_;
lfsr_data_t data; lfsr_data_t data;
int err = lfsr_rbyd_lookupnext(lfs, int err = lfsr_rbyd_lookupnext(lfs, &mdir->u.r.rbyd,
&mdir->u.r.rbyd, mdir->mid.rid, lfsr_tag_next(tag), mdir->mid & lfsr_mridmask(lfs), lfsr_tag_next(tag),
&rid, &tag, NULL, &data); &rid_, &tag, NULL, &data);
if (err && err != LFS_ERR_NOENT) { if (err && err != LFS_ERR_NOENT) {
return err; return err;
} }
if (err == LFS_ERR_NOENT || rid != mdir->mid.rid) { if (err == LFS_ERR_NOENT
|| rid_ != (mdir->mid & lfsr_mridmask(lfs))) {
break; break;
} }
// append the attr // append the attr
err = lfsr_rbyd_append(lfs, rbyd, err = lfsr_rbyd_append(lfs, rbyd,
lfs_smax32( rid - lfs_smax32(start_rid, 0),
attrs[i].rid - bid - lfs_smax32(start_rid, 0),
-1),
tag, 0, data); tag, 0, data);
if (err) { if (err) {
return err; return err;
@@ -2940,9 +2918,7 @@ static int lfsr_rbyd_appendattrs(lfs_t *lfs, lfsr_rbyd_t *rbyd,
LFS_ASSERT(!lfsr_tag_isinternal(attrs[i].tag)); LFS_ASSERT(!lfsr_tag_isinternal(attrs[i].tag));
int err = lfsr_rbyd_append(lfs, rbyd, int err = lfsr_rbyd_append(lfs, rbyd,
lfs_smax32( rid - lfs_smax32(start_rid, 0),
attrs[i].rid - bid - lfs_smax32(start_rid, 0),
-1),
attrs[i].tag, attrs[i].delta, attrs[i].data); attrs[i].tag, attrs[i].delta, attrs[i].data);
if (err) { if (err) {
return err; return err;
@@ -2952,10 +2928,10 @@ static int lfsr_rbyd_appendattrs(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// we need to make sure we keep start_rid/end_rid updated with // we need to make sure we keep start_rid/end_rid updated with
// weight changes // weight changes
if (lfs_smax32(attrs[i].rid - bid, -1) < start_rid) { if (rid < start_rid) {
start_rid += attrs[i].delta; start_rid += attrs[i].delta;
} }
if (lfs_smax32(attrs[i].rid - bid, -1) < end_rid) { if (rid < end_rid) {
end_rid += attrs[i].delta; end_rid += attrs[i].delta;
} }
} }
@@ -4691,7 +4667,7 @@ static bool lfsr_mdir_isopened(lfs_t *lfs,
// actual mdir functions // actual mdir functions
static int lfsr_mdir_fetch(lfs_t *lfs, lfsr_mdir_t *mdir, static int lfsr_mdir_fetch(lfs_t *lfs, lfsr_mdir_t *mdir,
const lfs_block_t blocks[static 2], lfsr_mid_t mid) { const lfs_block_t blocks[static 2], lfs_ssize_t mid) {
// create a copy of blocks, this is so we can swap the blocks // create a copy of blocks, this is so we can swap the blocks
// to keep track of the current revision, this also prevents issues // to keep track of the current revision, this also prevents issues
// if blocks points to the blocks in the mdir // if blocks points to the blocks in the mdir
@@ -4740,7 +4716,13 @@ static int lfsr_mdir_fetch(lfs_t *lfs, lfsr_mdir_t *mdir,
static int lfsr_mdir_lookup(lfs_t *lfs, const lfsr_mdir_t *mdir, static int lfsr_mdir_lookup(lfs_t *lfs, const lfsr_mdir_t *mdir,
lfs_ssize_t rid, lfsr_tag_t tag, lfs_ssize_t rid, lfsr_tag_t tag,
lfsr_tag_t *tag_, lfsr_data_t *data_) { lfsr_tag_t *tag_, lfsr_data_t *data_) {
return lfsr_rbyd_lookup(lfs, &mdir->u.r.rbyd, rid, tag, tag_, data_); return lfsr_rbyd_lookup(lfs, &mdir->u.r.rbyd,
// TODO anything better?
(rid == -1
? -1
: rid - (lfs_smax32(mdir->mid, 0) & lfsr_mbidmask(lfs))),
tag,
tag_, data_);
} }
@@ -4783,27 +4765,28 @@ static inline lfs_size_t lfsr_mtree_weight(lfs_t *lfs) {
return lfsr_btree_weight(&lfs->mtree); return lfsr_btree_weight(&lfs->mtree);
} }
static int lfsr_mtree_lookup(lfs_t *lfs, lfsr_mid_t mid, lfsr_mdir_t *mdir_) { static int lfsr_mtree_lookup(lfs_t *lfs, lfs_ssize_t mid, lfsr_mdir_t *mdir_) {
// looking up mroot? // looking up mroot?
if (lfsr_mtree_isinlined(lfs)) { if (lfsr_mtree_isinlined(lfs)) {
LFS_ASSERT(mid.bid == 0); LFS_ASSERT(mid >= 0);
LFS_ASSERT(mid < (lfs_ssize_t)lfsr_mbidweight(lfs));
mdir_->mid = mid; mdir_->mid = mid;
mdir_->u.m = lfs->mroot.u.m; mdir_->u.m = lfs->mroot.u.m;
return 0; return 0;
// look up mdir in actual mtree // look up mdir in actual mtree
} else { } else {
LFS_ASSERT(mid.bid >= 0); LFS_ASSERT(mid >= 0);
LFS_ASSERT(mid.bid < (lfs_ssize_t)lfsr_mtree_weight(lfs)); LFS_ASSERT(mid < (lfs_ssize_t)lfsr_mtree_weight(lfs));
lfs_size_t bid; lfs_size_t bid;
lfsr_tag_t tag; lfsr_tag_t tag;
lfsr_data_t data; lfsr_data_t data;
int err = lfsr_btree_lookupnext(lfs, &lfs->mtree, mid.bid, int err = lfsr_btree_lookupnext(lfs, &lfs->mtree, mid,
&bid, &tag, NULL, &data); &bid, &tag, NULL, &data);
if (err) { if (err) {
return err; return err;
} }
LFS_ASSERT(bid == (mid.bid | lfsr_mridmask(lfs))); LFS_ASSERT((lfs_ssize_t)bid == (mid | lfsr_mridmask(lfs)));
LFS_ASSERT(tag == LFSR_TAG_MDIR); LFS_ASSERT(tag == LFSR_TAG_MDIR);
// decode mdir // decode mdir
@@ -4831,7 +4814,7 @@ static int lfsr_mtree_parent(lfs_t *lfs, const lfs_block_t blocks[static 2],
while (true) { while (true) {
// fetch next possible superblock // fetch next possible superblock
lfsr_mdir_t mdir; lfsr_mdir_t mdir;
int err = lfsr_mdir_fetch(lfs, &mdir, blocks_, LFSR_MID(-1, -1)); int err = lfsr_mdir_fetch(lfs, &mdir, blocks_, -1);
if (err) { if (err) {
return err; return err;
} }
@@ -4859,29 +4842,29 @@ static int lfsr_mtree_parent(lfs_t *lfs, const lfs_block_t blocks[static 2],
} }
static int lfsr_mtree_seek(lfs_t *lfs, lfsr_mdir_t *mdir, lfs_off_t off) { static int lfsr_mtree_seek(lfs_t *lfs, lfsr_mdir_t *mdir, lfs_off_t off) {
// calculate new rid // calculate new mid, be careful to avoid rid overflow
lfs_ssize_t rid_ = mdir->mid.rid + off; lfs_size_t bid = mdir->mid & lfsr_mbidmask(lfs);
lfs_size_t rid = (mdir->mid & lfsr_mridmask(lfs)) + off;
// lookup mdirs until we find our rid, we need to do this because // lookup mdirs until we find our rid, we need to do this because
// we don't know how many rids are in each mdir until we fetch // we don't know how many rids are in each mdir until we fetch
while (rid_ >= (lfs_ssize_t)mdir->u.m.weight) { while (rid >= mdir->u.m.weight) {
lfsr_smbid_t bid_ = mdir->mid.bid + lfsr_mbidweight(lfs);
// end of mtree? // end of mtree?
if (bid_ >= (lfs_ssize_t)lfsr_mtree_weight(lfs)) { if (bid+lfsr_mbidweight(lfs) >= lfsr_mtree_weight(lfs)) {
// TODO is this needed? // if we hit the end of the mtree, park the mdir so all future
// make sure to update rid even if we error so seek will always // seeks return noent
// return noent after the first noent mdir->mid = bid + mdir->u.m.weight;
mdir->mid.rid = rid_;
return LFS_ERR_NOENT; return LFS_ERR_NOENT;
} }
rid_ -= mdir->u.m.weight;
int err = lfsr_mtree_lookup(lfs, LFSR_MID(bid_, rid_), mdir); bid += lfsr_mbidweight(lfs);
rid -= mdir->u.m.weight;
int err = lfsr_mtree_lookup(lfs, bid, mdir);
if (err) { if (err) {
return err; return err;
} }
} }
mdir->mid.rid = rid_; mdir->mid = bid + rid;
return 0; return 0;
} }
@@ -4890,6 +4873,7 @@ static int lfsr_mtree_seek(lfs_t *lfs, lfsr_mdir_t *mdir, lfs_off_t off) {
// - reason = compacting => only alloc if mdir is tired (wear-leveling) // - reason = compacting => only alloc if mdir is tired (wear-leveling)
// - reason = extending => never alloc (mroot anchor) // - reason = extending => never alloc (mroot anchor)
// - reason >= 0 => always alloc, use this as the new mid (new mdir) // - reason >= 0 => always alloc, use this as the new mid (new mdir)
// TODO make this -2/-3 or something
enum { enum {
LFSR_MDIR_COMPACTING = -3, LFSR_MDIR_COMPACTING = -3,
LFSR_MDIR_EXTENDING = -4, LFSR_MDIR_EXTENDING = -4,
@@ -4918,7 +4902,7 @@ static int lfsr_mdir_compact_(lfs_t *lfs, lfsr_mdir_t *mdir_,
// TODO rev things // TODO rev things
&& (rev + 1) % lfs->cfg->block_cycles == 0))) { && (rev + 1) % lfs->cfg->block_cycles == 0))) {
// assign the new mid // assign the new mid
mdir_->mid = LFSR_MID((reason >= 0 ? reason : mdir->mid.bid), -1); mdir_->mid = (reason >= 0 ? reason : mdir->mid);
// allocate two blocks // allocate two blocks
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
@@ -4992,7 +4976,8 @@ static int lfsr_mdir_compact_(lfs_t *lfs, lfsr_mdir_t *mdir_,
// //
// upper layers should make sure this can't fail by limiting the // upper layers should make sure this can't fail by limiting the
// maximum commit size // maximum commit size
err = lfsr_rbyd_appendattrs(lfs, &mdir_->u.r.rbyd, 0, start_rid, end_rid, err = lfsr_rbyd_appendattrs(lfs, &mdir_->u.r.rbyd,
lfs_smax32(mdir_->mid, 0) & lfsr_mbidmask(lfs), start_rid, end_rid,
attr1s, attr1_count); attr1s, attr1_count);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE); LFS_ASSERT(err != LFS_ERR_RANGE);
@@ -5001,7 +4986,8 @@ static int lfsr_mdir_compact_(lfs_t *lfs, lfsr_mdir_t *mdir_,
// note we don't filter attrs from our second pending list, this // note we don't filter attrs from our second pending list, this
// is used for some auxiliary attrs in lfsr_mdir_commit // is used for some auxiliary attrs in lfsr_mdir_commit
err = lfsr_rbyd_appendattrs(lfs, &mdir_->u.r.rbyd, 0, -1, -1, err = lfsr_rbyd_appendattrs(lfs, &mdir_->u.r.rbyd,
lfs_smax32(mdir_->mid, 0) & lfsr_mbidmask(lfs), -1, -1,
attr2s, attr2_count); attr2s, attr2_count);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE); LFS_ASSERT(err != LFS_ERR_RANGE);
@@ -5012,7 +4998,7 @@ static int lfsr_mdir_compact_(lfs_t *lfs, lfsr_mdir_t *mdir_,
// drop commit if weight goes to zero // drop commit if weight goes to zero
if (mdir_->u.m.weight == 0 if (mdir_->u.m.weight == 0
// unless we are an mroot // unless we are an mroot
&& !(mdir_->mid.bid == -1 && !(mdir_->mid == -1
|| (lfsr_mtree_isinlined(lfs) || (lfsr_mtree_isinlined(lfs)
&& reason == LFSR_MDIR_COMPACTING))) { && reason == LFSR_MDIR_COMPACTING))) {
// TODO should we just make our pcache not assert? // TODO should we just make our pcache not assert?
@@ -5027,7 +5013,7 @@ static int lfsr_mdir_compact_(lfs_t *lfs, lfsr_mdir_t *mdir_,
// this pushes gstate up into the mroot when relocating, and // this pushes gstate up into the mroot when relocating, and
// helps avoid corner case issues when splitting/dropping // helps avoid corner case issues when splitting/dropping
bool flushinggdelta = false; bool flushinggdelta = false;
if (mdir_->mid.bid == -1 if (mdir_->mid == -1
|| (lfsr_mtree_isinlined(lfs) || (lfsr_mtree_isinlined(lfs)
&& reason == LFSR_MDIR_COMPACTING) && reason == LFSR_MDIR_COMPACTING)
|| lfsr_mdir_cmp(mdir_->u.m.blocks, mdir->u.m.blocks) == 0) { || lfsr_mdir_cmp(mdir_->u.m.blocks, mdir->u.m.blocks) == 0) {
@@ -5072,7 +5058,8 @@ static int lfsr_mdir_commit_(lfs_t *lfs, lfsr_mdir_t *mdir,
// TODO let the lower rbyd layer handle this somehow? // TODO let the lower rbyd layer handle this somehow?
// mark mdir as unerased in case we fail // mark mdir as unerased in case we fail
mdir->u.r.rbyd.eoff = lfs->cfg->block_size; mdir->u.r.rbyd.eoff = lfs->cfg->block_size;
int err = lfsr_rbyd_appendattrs(lfs, &mdir_.u.r.rbyd, 0, start_rid, end_rid, int err = lfsr_rbyd_appendattrs(lfs, &mdir_.u.r.rbyd,
lfs_smax32(mdir_.mid, 0) & lfsr_mbidmask(lfs), start_rid, end_rid,
attrs, attr_count); attrs, attr_count);
if (err && err != LFS_ERR_RANGE) { if (err && err != LFS_ERR_RANGE) {
return err; return err;
@@ -5084,7 +5071,7 @@ static int lfsr_mdir_commit_(lfs_t *lfs, lfsr_mdir_t *mdir,
// drop commit if weight goes to zero // drop commit if weight goes to zero
if (mdir_.u.m.weight == 0 if (mdir_.u.m.weight == 0
// unless we are an mroot // unless we are an mroot
&& !(mdir_.mid.bid == -1 || lfsr_mtree_isinlined(lfs))) { && !(mdir_.mid == -1 || lfsr_mtree_isinlined(lfs))) {
// TODO move this up into lfsr_mdir_commit? // TODO move this up into lfsr_mdir_commit?
// consume gstate so we don't lose any info // consume gstate so we don't lose any info
int err = lfsr_fs_consumegdelta(lfs, mdir); int err = lfsr_fs_consumegdelta(lfs, mdir);
@@ -5160,9 +5147,12 @@ compact:;
static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir, static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
const lfsr_attr_t *attrs, lfs_size_t attr_count) { const lfsr_attr_t *attrs, lfs_size_t attr_count) {
LFS_ASSERT(!lfsr_mdir_isdropped(mdir)); LFS_ASSERT(!lfsr_mdir_isdropped(mdir));
LFS_ASSERT(mdir->mid.bid == -1 LFS_ASSERT(mdir->mid == -1
|| lfsr_mtree_isinlined(lfs) || lfsr_mtree_isinlined(lfs)
|| mdir->u.m.weight > 0); || mdir->u.m.weight > 0);
LFS_ASSERT(mdir->mid == -1
|| (lfs_size_t)(mdir->mid & lfsr_mridmask(lfs))
<= mdir->u.m.weight);
// parse out any pending gstate, these will get automatically xored // parse out any pending gstate, these will get automatically xored
// with on-disk gdeltas in lower-level functions // with on-disk gdeltas in lower-level functions
@@ -5202,7 +5192,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
// //
// TODO wait, do we need to update lfs->mroot and mdir eagerly // TODO wait, do we need to update lfs->mroot and mdir eagerly
// for the same reason? // for the same reason?
lfsr_mdir_t mroot_ = (mdir->mid.bid == -1 || lfsr_mtree_isinlined(lfs) lfsr_mdir_t mroot_ = (mdir->mid == -1 || lfsr_mtree_isinlined(lfs)
? mdir_ ? mdir_
: lfs->mroot); : lfs->mroot);
lfsr_mdir_t msibling_ = {.u.r.rbyd.trunk=0}; lfsr_mdir_t msibling_ = {.u.r.rbyd.trunk=0};
@@ -5213,7 +5203,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
// need to split? // need to split?
if (err == LFS_ERR_RANGE) { if (err == LFS_ERR_RANGE) {
// this should not happen unless we can't fit our mroot's metadata // this should not happen unless we can't fit our mroot's metadata
LFS_ASSERT(lfsr_mtree_isinlined(lfs) || mdir->mid.bid != -1); LFS_ASSERT(lfsr_mtree_isinlined(lfs) || mdir->mid != -1);
// if we're the mroot, create a new mtree, assume the upper layers // if we're the mroot, create a new mtree, assume the upper layers
// will take care of grafting our mtree into the mroot as needed // will take care of grafting our mtree into the mroot as needed
if (lfsr_mtree_isinlined(lfs)) { if (lfsr_mtree_isinlined(lfs)) {
@@ -5242,7 +5232,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
// compact into new mdir tags < split_rid // compact into new mdir tags < split_rid
int err = lfsr_mdir_compact_(lfs, &mdir_, int err = lfsr_mdir_compact_(lfs, &mdir_,
lfs_smax32(mdir->mid.bid, 0), 0, split_rid, lfs_smax32(mdir->mid, 0), 0, split_rid,
mdir, attrs, attr_count, NULL, 0); mdir, attrs, attr_count, NULL, 0);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE); LFS_ASSERT(err != LFS_ERR_RANGE);
@@ -5251,17 +5241,17 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
// compact into new mdir tags >= split_rid // compact into new mdir tags >= split_rid
err = lfsr_mdir_compact_(lfs, &msibling_, err = lfsr_mdir_compact_(lfs, &msibling_,
lfs_smax32(mdir->mid.bid, 0), split_rid, -1, lfs_smax32(mdir->mid, 0), split_rid, -1,
mdir, attrs, attr_count, NULL, 0); mdir, attrs, attr_count, NULL, 0);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_RANGE); LFS_ASSERT(err != LFS_ERR_RANGE);
return err; return err;
} }
LFS_DEBUG("Splitting mdir %"PRId16" 0x{%"PRIx32",%"PRIx32"} " LFS_DEBUG("Splitting mdir %"PRId32" 0x{%"PRIx32",%"PRIx32"} "
"-> 0x{%"PRIx32",%"PRIx32"}" "-> 0x{%"PRIx32",%"PRIx32"}"
", 0x{%"PRIx32",%"PRIx32"}", ", 0x{%"PRIx32",%"PRIx32"}",
mdir->mid.bid, mdir->mid,
mdir->u.m.blocks[0], mdir->u.m.blocks[1], mdir->u.m.blocks[0], mdir->u.m.blocks[1],
mdir_.u.m.blocks[0], mdir_.u.m.blocks[1], mdir_.u.m.blocks[0], mdir_.u.m.blocks[1],
msibling_.u.m.blocks[0], msibling_.u.m.blocks[1]); msibling_.u.m.blocks[0], msibling_.u.m.blocks[1]);
@@ -5271,11 +5261,11 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
// both siblings reduced to zero // both siblings reduced to zero
if (mdir_.u.m.weight == 0 && msibling_.u.m.weight == 0) { if (mdir_.u.m.weight == 0 && msibling_.u.m.weight == 0) {
LFS_DEBUG("Dropping mdir %"PRId16" 0x{%"PRIx32",%"PRIx32"}", LFS_DEBUG("Dropping mdir %"PRId32" 0x{%"PRIx32",%"PRIx32"}",
mdir_.mid.bid, mdir_.mid,
mdir_.u.m.blocks[0], mdir_.u.m.blocks[1]); mdir_.u.m.blocks[0], mdir_.u.m.blocks[1]);
LFS_DEBUG("Dropping mdir %"PRId16" 0x{%"PRIx32",%"PRIx32"}", LFS_DEBUG("Dropping mdir %"PRId32" 0x{%"PRIx32",%"PRIx32"}",
msibling_.mid.bid, msibling_.mid,
msibling_.u.m.blocks[0], msibling_.u.m.blocks[1]); msibling_.u.m.blocks[0], msibling_.u.m.blocks[1]);
// mark as dropped // mark as dropped
mdir_.u.r.rbyd.trunk = 0; mdir_.u.r.rbyd.trunk = 0;
@@ -5283,7 +5273,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
// update our mtree // update our mtree
int err = lfsr_btree_commit(lfs, &mtree_, LFSR_ATTRS( int err = lfsr_btree_commit(lfs, &mtree_, LFSR_ATTRS(
LFSR_ATTR(mdir_.mid.bid | lfsr_mridmask(lfs), LFSR_ATTR(mdir_.mid | lfsr_mridmask(lfs),
RM, -lfsr_mbidweight(lfs), NULL))); RM, -lfsr_mbidweight(lfs), NULL)));
if (err) { if (err) {
return err; return err;
@@ -5291,8 +5281,8 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
// one sibling reduced to zero // one sibling reduced to zero
} else if (msibling_.u.m.weight == 0) { } else if (msibling_.u.m.weight == 0) {
LFS_DEBUG("Dropping mdir %"PRId16" 0x{%"PRIx32",%"PRIx32"}", LFS_DEBUG("Dropping mdir %"PRId32" 0x{%"PRIx32",%"PRIx32"}",
msibling_.mid.bid, msibling_.mid,
msibling_.u.m.blocks[0], msibling_.u.m.blocks[1]); msibling_.u.m.blocks[0], msibling_.u.m.blocks[1]);
// mark as dropped // mark as dropped
@@ -5307,7 +5297,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
} }
int err = lfsr_btree_commit(lfs, &mtree_, LFSR_ATTRS( int err = lfsr_btree_commit(lfs, &mtree_, LFSR_ATTRS(
LFSR_ATTR(mdir_.mid.bid | lfsr_mridmask(lfs), LFSR_ATTR(mdir_.mid | lfsr_mridmask(lfs),
MDIR, 0, BUF(mdir_buf, mdir_dsize)))); MDIR, 0, BUF(mdir_buf, mdir_dsize))));
if (err) { if (err) {
return err; return err;
@@ -5315,8 +5305,8 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
// other sibling reduced to zero // other sibling reduced to zero
} else if (mdir_.u.m.weight == 0) { } else if (mdir_.u.m.weight == 0) {
LFS_DEBUG("Dropping mdir %"PRId16" 0x{%"PRIx32",%"PRIx32"}", LFS_DEBUG("Dropping mdir %"PRId32" 0x{%"PRIx32",%"PRIx32"}",
mdir_.mid.bid, mdir_.mid,
mdir_.u.m.blocks[0], mdir_.u.m.blocks[1]); mdir_.u.m.blocks[0], mdir_.u.m.blocks[1]);
// mark as dropped // mark as dropped
@@ -5331,7 +5321,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
} }
int err = lfsr_btree_commit(lfs, &mtree_, LFSR_ATTRS( int err = lfsr_btree_commit(lfs, &mtree_, LFSR_ATTRS(
LFSR_ATTR(msibling_.mid.bid | lfsr_mridmask(lfs), LFSR_ATTR(msibling_.mid | lfsr_mridmask(lfs),
MDIR, 0, BUF(msibling_buf, msibling_dsize)))); MDIR, 0, BUF(msibling_buf, msibling_dsize))));
if (err) { if (err) {
return err; return err;
@@ -5341,7 +5331,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
} else { } else {
// adjust our sibling's mid, do this here in case other sibling // adjust our sibling's mid, do this here in case other sibling
// was dropped // was dropped
msibling_.mid.bid += lfsr_mbidweight(lfs); msibling_.mid += lfsr_mbidweight(lfs);
// update out mtree // update out mtree
@@ -5350,7 +5340,8 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
// note we need to do this after playing out pending attrs in // note we need to do this after playing out pending attrs in
// case they introduce a new name! // case they introduce a new name!
lfsr_data_t split_data; lfsr_data_t split_data;
int err = lfsr_mdir_lookup(lfs, &msibling_, 0, LFSR_TAG_WIDE(NAME), int err = lfsr_mdir_lookup(lfs, &msibling_,
msibling_.mid & lfsr_mbidmask(lfs), LFSR_TAG_WIDE(NAME),
NULL, &split_data); NULL, &split_data);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_NOENT); LFS_ASSERT(err != LFS_ERR_NOENT);
@@ -5371,11 +5362,11 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
} }
err = lfsr_btree_commit(lfs, &mtree_, LFSR_ATTRS( err = lfsr_btree_commit(lfs, &mtree_, LFSR_ATTRS(
LFSR_ATTR(mdir_.mid.bid | lfsr_mridmask(lfs), LFSR_ATTR(mdir_.mid | lfsr_mridmask(lfs),
MDIR, 0, BUF(mdir_buf, mdir_dsize)), MDIR, 0, BUF(mdir_buf, mdir_dsize)),
LFSR_ATTR((mdir_.mid.bid | lfsr_mridmask(lfs))+1, LFSR_ATTR((mdir_.mid | lfsr_mridmask(lfs))+1,
BRANCH, +lfsr_mbidweight(lfs), DATA(split_data)), BRANCH, +lfsr_mbidweight(lfs), DATA(split_data)),
LFSR_ATTR(msibling_.mid.bid | lfsr_mridmask(lfs), LFSR_ATTR(msibling_.mid | lfsr_mridmask(lfs),
MDIR, 0, BUF(msibling_buf, msibling_dsize)))); MDIR, 0, BUF(msibling_buf, msibling_dsize))));
if (err) { if (err) {
return err; return err;
@@ -5387,9 +5378,9 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
// mdir reduced to zero? need to drop? // mdir reduced to zero? need to drop?
} else if (mdir_.u.m.weight == 0 } else if (mdir_.u.m.weight == 0
// unless we are an mroot // unless we are an mroot
&& !(mdir->mid.bid == -1 || lfsr_mtree_isinlined(lfs))) { && !(mdir->mid == -1 || lfsr_mtree_isinlined(lfs))) {
LFS_DEBUG("Dropping mdir %"PRId16" 0x{%"PRIx32",%"PRIx32"}", LFS_DEBUG("Dropping mdir %"PRId32" 0x{%"PRIx32",%"PRIx32"}",
mdir->mid.bid, mdir->mid,
mdir->u.m.blocks[0], mdir->u.m.blocks[1]); mdir->u.m.blocks[0], mdir->u.m.blocks[1]);
// mark as dropped // mark as dropped
@@ -5397,7 +5388,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
// update our mtree // update our mtree
int err = lfsr_btree_commit(lfs, &mtree_, LFSR_ATTRS( int err = lfsr_btree_commit(lfs, &mtree_, LFSR_ATTRS(
LFSR_ATTR(mdir->mid.bid | lfsr_mridmask(lfs), LFSR_ATTR(mdir->mid | lfsr_mridmask(lfs),
RM, -lfsr_mbidweight(lfs), NULL))); RM, -lfsr_mbidweight(lfs), NULL)));
if (err) { if (err) {
return err; return err;
@@ -5408,16 +5399,16 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
// need to relocate? // need to relocate?
} else if (lfsr_mdir_cmp(mdir->u.m.blocks, mdir_.u.m.blocks) != 0) { } else if (lfsr_mdir_cmp(mdir->u.m.blocks, mdir_.u.m.blocks) != 0) {
// relocate mroot // relocate mroot
if (mdir->mid.bid == -1 || lfsr_mtree_isinlined(lfs)) { if (mdir->mid == -1 || lfsr_mtree_isinlined(lfs)) {
// if we're relocating our root, just mark the root as dirty // if we're relocating our root, just mark the root as dirty
// and let our dirtymroot code handle this // and let our dirtymroot code handle this
dirtymroot = true; dirtymroot = true;
// relocate a normal mdir // relocate a normal mdir
} else { } else {
LFS_DEBUG("Relocating mdir %"PRId16" 0x{%"PRIx32",%"PRIx32"} " LFS_DEBUG("Relocating mdir %"PRId32" 0x{%"PRIx32",%"PRIx32"} "
"-> 0x{%"PRIx32",%"PRIx32"}", "-> 0x{%"PRIx32",%"PRIx32"}",
mdir->mid.bid, mdir->mid,
mdir->u.m.blocks[0], mdir->u.m.blocks[1], mdir->u.m.blocks[0], mdir->u.m.blocks[1],
mdir_.u.m.blocks[0], mdir_.u.m.blocks[1]); mdir_.u.m.blocks[0], mdir_.u.m.blocks[1]);
@@ -5430,7 +5421,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
} }
int err = lfsr_btree_commit(lfs, &mtree_, LFSR_ATTRS( int err = lfsr_btree_commit(lfs, &mtree_, LFSR_ATTRS(
LFSR_ATTR(mdir->mid.bid | lfsr_mridmask(lfs), LFSR_ATTR(mdir->mid | lfsr_mridmask(lfs),
MDIR, 0, BUF(mdir_buf, mdir_dsize)))); MDIR, 0, BUF(mdir_buf, mdir_dsize))));
if (err) { if (err) {
return err; return err;
@@ -5468,18 +5459,20 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
// fix our grm // fix our grm
for (uint8_t j = 0; j < 2; j++) { for (uint8_t j = 0; j < 2; j++) {
if (grm->rms[j].bid == lfs_smax32(mdir->mid.bid, 0)) { if ((grm->rms[j] & lfsr_mbidmask(lfs))
LFS_ASSERT(grm->rms[j].rid == (lfs_smax32(mdir->mid, 0) & lfsr_mbidmask(lfs))) {
LFS_ASSERT((grm->rms[j] & lfsr_mridmask(lfs))
<= (lfs_ssize_t)mdir->u.m.weight); <= (lfs_ssize_t)mdir->u.m.weight);
if (grm->rms[j].rid >= (lfs_ssize_t)mdir_.u.m.weight) { if ((grm->rms[j] & lfsr_mridmask(lfs))
grm->rms[j].bid += lfsr_mbidweight(lfs); >= (lfs_ssize_t)mdir_.u.m.weight) {
grm->rms[j].rid -= mdir_.u.m.weight; grm->rms[j] += lfsr_mbidweight(lfs)
- mdir_.u.m.weight;
} }
// update mid if we had a split or drop // update mid if we had a split or drop
} else if (grm->rms[j].bid > mdir->mid.bid } else if (grm->rms[j] > mdir->mid
&& lfsr_btree_weight(&mtree_) && lfsr_btree_weight(&mtree_)
!= lfsr_mtree_weight(lfs)) { != lfsr_mtree_weight(lfs)) {
grm->rms[j].bid += lfsr_btree_weight(&mtree_) grm->rms[j] += lfsr_btree_weight(&mtree_)
- lfsr_mtree_weight(lfs); - lfsr_mtree_weight(lfs);
} }
} }
@@ -5615,7 +5608,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
lfsr_mdir_t mparentroot = mchildroot; lfsr_mdir_t mparentroot = mchildroot;
// make sure all non-inlined mroots have mid=-1 // make sure all non-inlined mroots have mid=-1
// TODO should we assign the mroot mid in lfsr_mdir_compact_? // TODO should we assign the mroot mid in lfsr_mdir_compact_?
mparentroot.mid = LFSR_MID(-1, -1); mparentroot.mid = -1;
err = lfsr_mdir_compact_(lfs, &mparentroot, LFSR_MDIR_EXTENDING, 0, 0, err = lfsr_mdir_compact_(lfs, &mparentroot, LFSR_MDIR_EXTENDING, 0, 0,
&mchildroot, NULL, 0, LFSR_ATTRS( &mchildroot, NULL, 0, LFSR_ATTRS(
LFSR_ATTR(-1, SUPERMAGIC, 0, DATA(magic)), LFSR_ATTR(-1, SUPERMAGIC, 0, DATA(magic)),
@@ -5660,17 +5653,18 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
// mdirs and normal dirs which are pairs of mdirs // mdirs and normal dirs which are pairs of mdirs
for (uint8_t j = 0; j <= type; j++) { for (uint8_t j = 0; j <= type; j++) {
lfsr_mdir_t *opened_mdir = &(&opened->mdir)[j]; lfsr_mdir_t *opened_mdir = &(&opened->mdir)[j];
LFS_ASSERT(opened_mdir->mid.bid >= 0); LFS_ASSERT(opened_mdir->mid >= 0);
// first play out any attrs that change our rid // first play out any attrs that change our rid
for (lfs_size_t i = 0; i < attr_count; i++) { for (lfs_size_t i = 0; i < attr_count; i++) {
// TODO clean this up a bit? // TODO clean this up a bit?
// adjust opened mdirs? // adjust opened mdirs?
if (opened_mdir->mid.bid == lfs_smax32(mdir->mid.bid, 0) if ((opened_mdir->mid & lfsr_mbidmask(lfs))
&& opened_mdir->mid.rid >= attrs[i].rid) { == (lfs_smax32(mdir->mid, 0)
& lfsr_mbidmask(lfs))
&& (opened_mdir->mid >= attrs[i].rid)) {
// removed? // removed?
if (opened_mdir->mid.rid if (opened_mdir->mid < attrs[i].rid - attrs[i].delta) {
< attrs[i].rid - attrs[i].delta) {
// normal mdirs mark as dropped // normal mdirs mark as dropped
if (j == 0) { if (j == 0) {
opened_mdir->u.r.rbyd.trunk = 0; opened_mdir->u.r.rbyd.trunk = 0;
@@ -5678,9 +5672,9 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
} }
// for dir's second mdir (the position mdir), move // for dir's second mdir (the position mdir), move
// on to the next rid // on to the next rid
opened_mdir->mid.rid = attrs[i].rid; opened_mdir->mid = attrs[i].rid;
} else { } else {
opened_mdir->mid.rid += attrs[i].delta; opened_mdir->mid += attrs[i].delta;
// adjust dir position? // adjust dir position?
if (type == LFS_TYPE_DIR && j == 0) { if (type == LFS_TYPE_DIR && j == 0) {
((lfsr_dir_t*)opened)->pos -= attrs[i].delta; ((lfsr_dir_t*)opened)->pos -= attrs[i].delta;
@@ -5688,7 +5682,7 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
((lfsr_dir_t*)opened)->pos += attrs[i].delta; ((lfsr_dir_t*)opened)->pos += attrs[i].delta;
} }
} }
} else if (opened_mdir->mid.bid > mdir->mid.bid) { } else if (opened_mdir->mid > mdir->mid) {
// adjust dir position? // adjust dir position?
if (type == LFS_TYPE_DIR && j == 0) { if (type == LFS_TYPE_DIR && j == 0) {
((lfsr_dir_t*)opened)->pos -= attrs[i].delta; ((lfsr_dir_t*)opened)->pos -= attrs[i].delta;
@@ -5699,20 +5693,21 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
} }
// update any opened mdirs if we had a split or drop // update any opened mdirs if we had a split or drop
if (opened_mdir->mid.bid == lfs_smax32(mdir->mid.bid, 0)) { if ((opened_mdir->mid & lfsr_mbidmask(lfs))
== (lfs_smax32(mdir->mid, 0) & lfsr_mbidmask(lfs))) {
if (!lfsr_mdir_isdropped(&msibling_) if (!lfsr_mdir_isdropped(&msibling_)
&& opened_mdir->mid.rid && (opened_mdir->mid & lfsr_mridmask(lfs))
>= (lfs_ssize_t)mdir_.u.m.weight) { >= (lfs_ssize_t)mdir_.u.m.weight) {
LFS_ASSERT(lfsr_btree_weight(&mtree_) LFS_ASSERT(lfsr_btree_weight(&mtree_)
!= lfsr_mtree_weight(lfs)); != lfsr_mtree_weight(lfs));
opened_mdir->mid.bid += lfsr_mbidweight(lfs); opened_mdir->mid += lfsr_mbidweight(lfs)
opened_mdir->mid.rid -= mdir_.u.m.weight; - mdir_.u.m.weight;
opened_mdir->u.m = msibling_.u.m; opened_mdir->u.m = msibling_.u.m;
} else { } else {
opened_mdir->u.m = mdir_.u.m; opened_mdir->u.m = mdir_.u.m;
} }
} else if (opened_mdir->mid.bid > mdir->mid.bid) { } else if (opened_mdir->mid > mdir->mid) {
opened_mdir->mid.bid += lfsr_btree_weight(&mtree_) opened_mdir->mid += lfsr_btree_weight(&mtree_)
- lfsr_mtree_weight(lfs); - lfsr_mtree_weight(lfs);
} }
} }
@@ -5721,13 +5716,15 @@ static int lfsr_mdir_commit(lfs_t *lfs, lfsr_mdir_t *mdir,
} }
// update mdir to follow requested rid // update mdir to follow requested rid
LFS_ASSERT(mdir->mid.rid <= (lfs_ssize_t)mdir->u.m.weight); if (mdir->mid != -1
if (mdir->mid.bid != -1
&& !lfsr_mdir_isdropped(&msibling_) && !lfsr_mdir_isdropped(&msibling_)
&& mdir->mid.rid >= (lfs_ssize_t)mdir_.u.m.weight) { && (mdir->mid & lfsr_mridmask(lfs))
LFS_ASSERT(lfsr_btree_weight(&mtree_) != lfsr_mtree_weight(lfs)); >= (lfs_ssize_t)mdir_.u.m.weight) {
mdir->mid.bid += lfsr_mbidweight(lfs); // TODO this can happen if we split+drop while removing this mid,
mdir->mid.rid -= mdir_.u.m.weight; // can we still assert for this?
//LFS_ASSERT(lfsr_btree_weight(&mtree_) != lfsr_mtree_weight(lfs));
mdir->mid += lfsr_mbidweight(lfs)
- mdir_.u.m.weight;
mdir->u.m = msibling_.u.m; mdir->u.m = msibling_.u.m;
} else { } else {
mdir->u.m = mdir_.u.m; mdir->u.m = mdir_.u.m;
@@ -5769,7 +5766,7 @@ static int lfsr_mtree_namelookup(lfs_t *lfs,
if (lfsr_mtree_isinlined(lfs)) { if (lfsr_mtree_isinlined(lfs)) {
mdir = lfs->mroot; mdir = lfs->mroot;
// treat inlined mdir as mid=0 // treat inlined mdir as mid=0
mdir.mid = LFSR_MID(0, -1); mdir.mid = 0;
// lookup name in actual mtree // lookup name in actual mtree
} else { } else {
@@ -5784,6 +5781,7 @@ static int lfsr_mtree_namelookup(lfs_t *lfs,
return err; return err;
} }
LFS_ASSERT(tag == LFSR_TAG_MDIR); LFS_ASSERT(tag == LFSR_TAG_MDIR);
LFS_ASSERT(weight == lfsr_mbidweight(lfs));
// decode mdir // decode mdir
err = lfsr_data_readmdir(lfs, &data, mdir.u.m.blocks); err = lfsr_data_readmdir(lfs, &data, mdir.u.m.blocks);
@@ -5792,8 +5790,7 @@ static int lfsr_mtree_namelookup(lfs_t *lfs,
} }
// fetch mdir // fetch mdir
err = lfsr_mdir_fetch(lfs, &mdir, mdir.u.m.blocks, err = lfsr_mdir_fetch(lfs, &mdir, mdir.u.m.blocks, bid-(weight-1));
LFSR_MID(bid-(weight-1), -1));
if (err) { if (err) {
return err; return err;
} }
@@ -5806,7 +5803,7 @@ static int lfsr_mtree_namelookup(lfs_t *lfs,
&rid, tag_, data_); &rid, tag_, data_);
// update mdir weith best place to insert even if we fail // update mdir weith best place to insert even if we fail
mdir.mid.rid = rid; mdir.mid += rid;
if (mdir_) { if (mdir_) {
*mdir_ = mdir; *mdir_ = mdir;
} }
@@ -5831,7 +5828,7 @@ static int lfsr_mtree_pathlookup(lfs_t *lfs, const char *path,
lfs_size_t *did_, const char **name_, lfs_size_t *name_size_) { lfs_size_t *did_, const char **name_, lfs_size_t *name_size_) {
// setup root // setup root
lfsr_mdir_t mdir; lfsr_mdir_t mdir;
mdir.mid = LFSR_MID(0, 0); mdir.mid = 0;
lfsr_tag_t tag = LFSR_TAG_DIR; lfsr_tag_t tag = LFSR_TAG_DIR;
lfs_size_t did = LFSR_DID_ROOT; lfs_size_t did = LFSR_DID_ROOT;
@@ -5899,7 +5896,7 @@ static int lfsr_mtree_pathlookup(lfs_t *lfs, const char *path,
// read the next did from the mdir if this is not the root // read the next did from the mdir if this is not the root
if (!lfsr_mid_isroot(mdir.mid)) { if (!lfsr_mid_isroot(mdir.mid)) {
lfsr_data_t data; lfsr_data_t data;
int err = lfsr_mdir_lookup(lfs, &mdir, mdir.mid.rid, LFSR_TAG_DID, int err = lfsr_mdir_lookup(lfs, &mdir, mdir.mid, LFSR_TAG_DID,
NULL, &data); NULL, &data);
if (err) { if (err) {
return err; return err;
@@ -5986,7 +5983,7 @@ enum {
static int lfsr_mtree_traversal_next(lfs_t *lfs, static int lfsr_mtree_traversal_next(lfs_t *lfs,
lfsr_mtree_traversal_t *traversal, lfsr_mtree_traversal_t *traversal,
lfsr_mid_t *mid_, lfsr_tag_t *tag_, lfsr_data_t *data_) { lfs_ssize_t *mid_, lfsr_tag_t *tag_, lfsr_data_t *data_) {
// new traversal? start with 0x{0,1} // new traversal? start with 0x{0,1}
// //
// note we make sure to include all mroots in our mroot chain! // note we make sure to include all mroots in our mroot chain!
@@ -5994,13 +5991,13 @@ static int lfsr_mtree_traversal_next(lfs_t *lfs,
if (traversal->mdir.u.r.rbyd.trunk == 0) { if (traversal->mdir.u.r.rbyd.trunk == 0) {
// fetch the first mroot 0x{0,1} // fetch the first mroot 0x{0,1}
int err = lfsr_mdir_fetch(lfs, &traversal->mdir, int err = lfsr_mdir_fetch(lfs, &traversal->mdir,
LFSR_MDIR_MROOTANCHOR, LFSR_MID(-1, -1)); LFSR_MDIR_MROOTANCHOR, -1);
if (err) { if (err) {
return err; return err;
} }
if (mid_) { if (mid_) {
*mid_ = LFSR_MID(-1, -1); *mid_ = -1;
} }
if (tag_) { if (tag_) {
*tag_ = LFSR_TAG_MDIR; *tag_ = LFSR_TAG_MDIR;
@@ -6011,7 +6008,7 @@ static int lfsr_mtree_traversal_next(lfs_t *lfs,
return 0; return 0;
// check for mroot/mtree/mdir // check for mroot/mtree/mdir
} else if (traversal->mdir.mid.bid == -1) { } else if (traversal->mdir.mid == -1) {
// lookup mroot, if we find one this is a fake mroot // lookup mroot, if we find one this is a fake mroot
lfsr_tag_t tag; lfsr_tag_t tag;
lfsr_data_t data; lfsr_data_t data;
@@ -6057,13 +6054,13 @@ static int lfsr_mtree_traversal_next(lfs_t *lfs,
// fetch this mroot // fetch this mroot
err = lfsr_mdir_fetch(lfs, &traversal->mdir, err = lfsr_mdir_fetch(lfs, &traversal->mdir,
traversal->mdir.u.m.blocks, LFSR_MID(-1, -1)); traversal->mdir.u.m.blocks, -1);
if (err) { if (err) {
return err; return err;
} }
if (mid_) { if (mid_) {
*mid_ = LFSR_MID(-1, -1); *mid_ = -1;
} }
if (tag_) { if (tag_) {
*tag_ = LFSR_TAG_MDIR; *tag_ = LFSR_TAG_MDIR;
@@ -6156,10 +6153,10 @@ static int lfsr_mtree_traversal_next(lfs_t *lfs,
// still update our mdir mid so we don't get stuck in a loop // still update our mdir mid so we don't get stuck in a loop
// traversing mroots // traversing mroots
traversal->mdir.mid.bid = bid; traversal->mdir.mid = bid;
if (mid_) { if (mid_) {
*mid_ = LFSR_MID(bid, -1); *mid_ = bid;
} }
if (tag_) { if (tag_) {
*tag_ = tag; *tag_ = tag;
@@ -6177,13 +6174,13 @@ static int lfsr_mtree_traversal_next(lfs_t *lfs,
} }
err = lfsr_mdir_fetch(lfs, &traversal->mdir, err = lfsr_mdir_fetch(lfs, &traversal->mdir,
traversal->mdir.u.m.blocks, LFSR_MID(bid, -1)); traversal->mdir.u.m.blocks, bid);
if (err) { if (err) {
return err; return err;
} }
if (mid_) { if (mid_) {
*mid_ = LFSR_MID(bid, -1); *mid_ = bid;
} }
if (tag_) { if (tag_) {
*tag_ = tag; *tag_ = tag;
@@ -6325,7 +6322,7 @@ static int lfsr_mountinited(lfs_t *lfs) {
lfsr_mdir_t *mdir = (lfsr_mdir_t*)data.u.b.buffer; lfsr_mdir_t *mdir = (lfsr_mdir_t*)data.u.b.buffer;
// found an mroot? // found an mroot?
if (mdir->mid.bid == -1) { if (mdir->mid == -1) {
// has magic string? // has magic string?
lfsr_data_t data; lfsr_data_t data;
err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_SUPERMAGIC, err = lfsr_mdir_lookup(lfs, mdir, -1, LFSR_TAG_SUPERMAGIC,
@@ -6567,11 +6564,9 @@ static int lfsr_mountinited(lfs_t *lfs) {
} }
if (lfsr_grm_hasrm(&lfs->grm)) { if (lfsr_grm_hasrm(&lfs->grm)) {
LFS_DEBUG("Found pending grm %"PRId16".%"PRId16" %"PRId16".%"PRId16, LFS_DEBUG("Found pending grm %"PRId32" %"PRId32,
lfs->grm.rms[0].bid, lfs->grm.rms[0],
lfs->grm.rms[0].rid, lfs->grm.rms[1]);
lfs->grm.rms[1].bid,
lfs->grm.rms[1].rid);
} }
return 0; return 0;
@@ -6886,12 +6881,12 @@ int lfsr_mkdir(lfs_t *lfs, const char *path) {
// commit our new directory into our parent, creating a grm to self-remove // commit our new directory into our parent, creating a grm to self-remove
// in case of powerloss // in case of powerloss
err = lfsr_mdir_commit(lfs, &mdir, LFSR_ATTRS( err = lfsr_mdir_commit(lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(mdir.mid.rid, DIR, +1, LFSR_ATTR(mdir.mid, DIR, +1,
NAME(did, name, name_size)), NAME(did, name, name_size)),
LFSR_ATTR(mdir.mid.rid, DID, 0, LEB128(did_)), LFSR_ATTR(mdir.mid, DID, 0, LEB128(did_)),
LFSR_ATTR(-1, GRM, 0, GRM(&((lfsr_grm_t){{ LFSR_ATTR(-1, GRM, 0, GRM(&((lfsr_grm_t){{
mdir.mid, mdir.mid,
LFSR_MID(-1, -1)}}))))); -1}})))));
if (err) { if (err) {
goto failed_with_bookmark; goto failed_with_bookmark;
} }
@@ -6901,10 +6896,10 @@ int lfsr_mkdir(lfs_t *lfs, const char *path) {
// commit our bookmark and zero the grm, the bookmark tag is an empty // commit our bookmark and zero the grm, the bookmark tag is an empty
// entry that marks our did as allocated // entry that marks our did as allocated
err = lfsr_mdir_commit(lfs, &bookmark.mdir, LFSR_ATTRS( err = lfsr_mdir_commit(lfs, &bookmark.mdir, LFSR_ATTRS(
LFSR_ATTR(bookmark.mdir.mid.rid, BOOKMARK, +1, NAME(did_, NULL, 0)), LFSR_ATTR(bookmark.mdir.mid, BOOKMARK, +1, NAME(did_, NULL, 0)),
LFSR_ATTR(-1, GRM, 0, GRM(&((lfsr_grm_t){{ LFSR_ATTR(-1, GRM, 0, GRM(&((lfsr_grm_t){{
LFSR_MID(-1, -1), -1,
LFSR_MID(-1, -1)}}))))); -1}})))));
if (err) { if (err) {
return err; return err;
} }
@@ -6939,7 +6934,7 @@ int lfsr_remove(lfs_t *lfs, const char *path) {
if (tag == LFSR_TAG_DIR) { if (tag == LFSR_TAG_DIR) {
// first lets figure out the did // first lets figure out the did
lfsr_data_t data; lfsr_data_t data;
int err = lfsr_mdir_lookup(lfs, &mdir, mdir.mid.rid, LFSR_TAG_DID, int err = lfsr_mdir_lookup(lfs, &mdir, mdir.mid, LFSR_TAG_DID,
NULL, &data); NULL, &data);
if (err) { if (err) {
return err; return err;
@@ -6972,7 +6967,7 @@ int lfsr_remove(lfs_t *lfs, const char *path) {
if (err != LFS_ERR_NOENT) { if (err != LFS_ERR_NOENT) {
lfsr_tag_t bookmark_tag; lfsr_tag_t bookmark_tag;
err = lfsr_mdir_lookup(lfs, &bookmark_mdir, err = lfsr_mdir_lookup(lfs, &bookmark_mdir,
bookmark_mdir.mid.rid, LFSR_TAG_WIDE(NAME), bookmark_mdir.mid, LFSR_TAG_WIDE(NAME),
&bookmark_tag, NULL); &bookmark_tag, NULL);
if (err) { if (err) {
return err; return err;
@@ -6984,15 +6979,16 @@ int lfsr_remove(lfs_t *lfs, const char *path) {
} }
// adjust rid if grm is on the same mdir as our dir // adjust rid if grm is on the same mdir as our dir
if (grm.rms[0].bid == mdir.mid.bid if ((grm.rms[0] & lfsr_mbidmask(lfs))
&& grm.rms[0].rid > mdir.mid.rid) { == (mdir.mid & lfsr_mbidmask(lfs))
grm.rms[0].rid -= 1; && grm.rms[0] > mdir.mid) {
grm.rms[0] -= 1;
} }
} }
// remove the metadata entry // remove the metadata entry
err = lfsr_mdir_commit(lfs, &mdir, LFSR_ATTRS( err = lfsr_mdir_commit(lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(mdir.mid.rid, RM, -1, NULL), LFSR_ATTR(mdir.mid, RM, -1, NULL),
LFSR_ATTR(-1, GRM, 0, GRM(&grm)))); LFSR_ATTR(-1, GRM, 0, GRM(&grm))));
if (err) { if (err) {
return err; return err;
@@ -7046,9 +7042,10 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) {
} }
// adjust old rid if grm is on the same mdir as new rid // adjust old rid if grm is on the same mdir as new rid
if (grm.rms[0].bid == new_mdir.mid.bid if ((grm.rms[0] & lfsr_mbidmask(lfs))
&& grm.rms[0].rid >= new_mdir.mid.rid) { == (new_mdir.mid & lfsr_mbidmask(lfs))
grm.rms[0].rid += 1; && grm.rms[0] >= new_mdir.mid) {
grm.rms[0] += 1;
} }
} else { } else {
@@ -7059,8 +7056,7 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) {
// TODO is it? is this check necessary? // TODO is it? is this check necessary?
// renaming to ourself is a noop // renaming to ourself is a noop
if (old_mdir.mid.bid == new_mdir.mid.bid if (old_mdir.mid == new_mdir.mid) {
&& old_mdir.mid.rid == new_mdir.mid.rid) {
return 0; return 0;
} }
@@ -7071,7 +7067,7 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) {
// first lets figure out the did // first lets figure out the did
lfsr_data_t data; lfsr_data_t data;
int err = lfsr_mdir_lookup(lfs, &new_mdir, int err = lfsr_mdir_lookup(lfs, &new_mdir,
new_mdir.mid.rid, LFSR_TAG_DID, new_mdir.mid, LFSR_TAG_DID,
NULL, &data); NULL, &data);
if (err) { if (err) {
return err; return err;
@@ -7104,7 +7100,7 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) {
if (err != LFS_ERR_NOENT) { if (err != LFS_ERR_NOENT) {
lfsr_tag_t bookmark_tag; lfsr_tag_t bookmark_tag;
err = lfsr_mdir_lookup(lfs, &bookmark_mdir, err = lfsr_mdir_lookup(lfs, &bookmark_mdir,
bookmark_mdir.mid.rid, LFSR_TAG_WIDE(NAME), bookmark_mdir.mid, LFSR_TAG_WIDE(NAME),
&bookmark_tag, NULL); &bookmark_tag, NULL);
if (err) { if (err) {
return err; return err;
@@ -7121,11 +7117,11 @@ int lfsr_rename(lfs_t *lfs, const char *old_path, const char *new_path) {
// new rid, while also marking the old rid for removal // new rid, while also marking the old rid for removal
err = lfsr_mdir_commit(lfs, &new_mdir, LFSR_ATTRS( err = lfsr_mdir_commit(lfs, &new_mdir, LFSR_ATTRS(
(exists (exists
? LFSR_ATTR(new_mdir.mid.rid, RM, -1, NULL) ? LFSR_ATTR(new_mdir.mid, RM, -1, NULL)
: LFSR_ATTR_NOOP), : LFSR_ATTR_NOOP),
LFSR_ATTR(new_mdir.mid.rid, TAG(old_tag), +1, LFSR_ATTR(new_mdir.mid, TAG(old_tag), +1,
NAME(new_did, new_name, new_name_size)), NAME(new_did, new_name, new_name_size)),
LFSR_ATTR(new_mdir.mid.rid, MOVE, 0, MOVE(&old_mdir)), LFSR_ATTR(new_mdir.mid, MOVE, 0, MOVE(&old_mdir)),
LFSR_ATTR(-1, GRM, 0, GRM(&grm)))); LFSR_ATTR(-1, GRM, 0, GRM(&grm))));
// we need to clean up any pending grms, fortunately we can leave // we need to clean up any pending grms, fortunately we can leave
@@ -7188,7 +7184,7 @@ int lfsr_dir_open(lfs_t *lfs, lfsr_dir_t *dir, const char *path) {
dir->did = 0; dir->did = 0;
} else { } else {
lfsr_data_t data; lfsr_data_t data;
int err = lfsr_mdir_lookup(lfs, &mdir, mdir.mid.rid, LFSR_TAG_DID, int err = lfsr_mdir_lookup(lfs, &mdir, mdir.mid, LFSR_TAG_DID,
NULL, &data); NULL, &data);
if (err) { if (err) {
return err; return err;
@@ -7251,7 +7247,7 @@ int lfsr_dir_read(lfs_t *lfs, lfsr_dir_t *dir, struct lfs_info *info) {
lfsr_tag_t tag; lfsr_tag_t tag;
lfsr_data_t data; lfsr_data_t data;
err = lfsr_mdir_lookup(lfs, &dir->pos_mdir, err = lfsr_mdir_lookup(lfs, &dir->pos_mdir,
dir->pos_mdir.mid.rid, LFSR_TAG_WIDE(NAME), dir->pos_mdir.mid, LFSR_TAG_WIDE(NAME),
&tag, &data); &tag, &data);
if (err) { if (err) {
return err; return err;
@@ -7348,8 +7344,8 @@ static int lfsr_fs_fixgrm(lfs_t *lfs) {
while (lfsr_grm_hasrm(&lfs->grm)) { while (lfsr_grm_hasrm(&lfs->grm)) {
// find our mdir // find our mdir
lfsr_mdir_t mdir; lfsr_mdir_t mdir;
LFS_ASSERT(lfs->grm.rms[0].bid LFS_ASSERT(lfs->grm.rms[0]
< lfs_smax32(lfsr_mtree_weight(lfs), 1)); < lfs_smax32(lfsr_mtree_weight(lfs), lfsr_mbidweight(lfs)));
int err = lfsr_mtree_lookup(lfs, lfs->grm.rms[0], &mdir); int err = lfsr_mtree_lookup(lfs, lfs->grm.rms[0], &mdir);
if (err) { if (err) {
return err; return err;
@@ -7360,16 +7356,18 @@ static int lfsr_fs_fixgrm(lfs_t *lfs) {
lfsr_grm_poprm(&grm); lfsr_grm_poprm(&grm);
// make sure to adjust any remaining grms // make sure to adjust any remaining grms
if (grm.rms[0].bid == mdir.mid.bid if ((grm.rms[0] & lfsr_mbidmask(lfs))
&& grm.rms[0].rid >= mdir.mid.rid) { == (mdir.mid & lfsr_mbidmask(lfs))
LFS_ASSERT(grm.rms[0].rid != mdir.mid.rid); && grm.rms[0] >= mdir.mid) {
grm.rms[0].rid -= 1; LFS_ASSERT(grm.rms[0] != mdir.mid);
grm.rms[0] -= 1;
} }
// remove the rid while also updating our grm // remove the rid while also updating our grm
LFS_ASSERT(lfs->grm.rms[0].rid < (lfs_ssize_t)mdir.u.m.weight); LFS_ASSERT((lfs->grm.rms[0] & lfsr_mridmask(lfs))
< (lfs_ssize_t)mdir.u.m.weight);
err = lfsr_mdir_commit(lfs, &mdir, LFSR_ATTRS( err = lfsr_mdir_commit(lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(mdir.mid.rid, RM, -1, NULL), LFSR_ATTR(mdir.mid, RM, -1, NULL),
LFSR_ATTR(-1, GRM, 0, GRM(&grm)))); LFSR_ATTR(-1, GRM, 0, GRM(&grm))));
} }
@@ -7382,11 +7380,9 @@ static int lfsr_fs_preparemutation(lfs_t *lfs) {
// fix pending grms // fix pending grms
if (lfsr_grm_hasrm(&lfs->grm)) { if (lfsr_grm_hasrm(&lfs->grm)) {
LFS_DEBUG("Fixing grm %"PRId16".%"PRId16" %"PRId16".%"PRId16, LFS_DEBUG("Fixing grm %"PRId32" %"PRId32,
lfs->grm.rms[0].bid, lfs->grm.rms[0],
lfs->grm.rms[0].rid, lfs->grm.rms[1]);
lfs->grm.rms[1].bid,
lfs->grm.rms[1].rid);
int err = lfsr_fs_fixgrm(lfs); int err = lfsr_fs_fixgrm(lfs);
if (err) { if (err) {
+2 -12
View File
@@ -47,16 +47,6 @@ typedef uint32_t lfs_block_t;
typedef uint16_t lfsr_tag_t; typedef uint16_t lfsr_tag_t;
typedef int16_t lfsr_stag_t; typedef int16_t lfsr_stag_t;
typedef uint32_t lfsr_mbid_t;
typedef int32_t lfsr_smbid_t;
typedef uint32_t lfsr_mrid_t;
typedef int32_t lfsr_smrid_t;
typedef struct lfsr_mid {
lfsr_smbid_t bid;
lfsr_smrid_t rid;
} lfsr_mid_t;
// Maximum name size in bytes, may be redefined to reduce the size of the // Maximum name size in bytes, may be redefined to reduce the size of the
// info struct. Limited to <= 1022. Stored in superblock and must be // info struct. Limited to <= 1022. Stored in superblock and must be
// respected by other littlefs drivers. // respected by other littlefs drivers.
@@ -380,7 +370,7 @@ typedef struct lfsr_btree {
} lfsr_btree_t; } lfsr_btree_t;
typedef struct lfsr_mdir { typedef struct lfsr_mdir {
lfsr_mid_t mid; lfs_ssize_t mid;
union { union {
// here we make sure to line up our block array so it overlaps with // here we make sure to line up our block array so it overlaps with
// the block stored as the first entry in the rbyd // the block stored as the first entry in the rbyd
@@ -412,7 +402,7 @@ typedef struct lfsr_openedmdir {
#define LFSR_GRM_DSIZE (1+5+5+5+5) #define LFSR_GRM_DSIZE (1+5+5+5+5)
typedef struct lfsr_grm { typedef struct lfsr_grm {
lfsr_mid_t rms[2]; lfs_ssize_t rms[2];
} lfsr_grm_t; } lfsr_grm_t;
+12 -11
View File
@@ -109,9 +109,8 @@ code = '''
LFSR_ATTR(0, RM, -1, NULL))) => 0; LFSR_ATTR(0, RM, -1, NULL))) => 0;
lfsr_mdir_t mdir; lfsr_mdir_t mdir;
lfsr_mtree_lookup(&lfs, LFSR_MID(0, -1), lfsr_mtree_lookup(&lfs, 0*lfsr_mbidweight(&lfs)+0,
&mdir) => 0; &mdir) => 0;
mdir.mid.rid = 0;
lfs_size_t count = 0; lfs_size_t count = 0;
while (true) { while (true) {
@@ -123,7 +122,7 @@ code = '''
// keep creating new metadata entries until we run out of space // keep creating new metadata entries until we run out of space
int err = lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS( int err = lfsr_mdir_commit(&lfs, &mdir, LFSR_ATTRS(
LFSR_ATTR(mdir.mid.rid, REG, +1, LFSR_ATTR(mdir.mid, REG, +1,
BUF(&alphas[count % 26], 1)))); BUF(&alphas[count % 26], 1))));
assert(!err || err == LFS_ERR_NOSPC); assert(!err || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) { if (err == LFS_ERR_NOSPC) {
@@ -131,12 +130,12 @@ code = '''
} }
uint8_t buffer[4]; uint8_t buffer[4];
lfsr_mdir_get(&lfs, &mdir, mdir.mid.rid, LFSR_TAG_REG, lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG,
buffer, 4) => 1; buffer, 4) => 1;
assert(memcmp(buffer, &alphas[count % 26], 1) == 0); assert(memcmp(buffer, &alphas[count % 26], 1) == 0);
mdir.mid += 1;
count += 1; count += 1;
mdir.mid.rid += 1;
} }
printf("alloced %d metadata entries in %d blocks\n", printf("alloced %d metadata entries in %d blocks\n",
@@ -145,15 +144,17 @@ code = '''
// test that all of our metadata entries are still there // test that all of our metadata entries are still there
lfs_size_t i = 0; lfs_size_t i = 0;
for (lfs_ssize_t mid = 0; for (lfs_ssize_t mid = 0;
mid < lfs_smax32(lfsr_mtree_weight(&lfs), 1); mid < lfs_smax32(
lfsr_mtree_weight(&lfs),
lfsr_mbidweight(&lfs));
mid += lfsr_mbidweight(&lfs)) { mid += lfsr_mbidweight(&lfs)) {
lfsr_mdir_t mdir; lfsr_mdir_t mdir;
lfsr_mtree_lookup(&lfs, LFSR_MID(mid, -1), &mdir) => 0; lfsr_mtree_lookup(&lfs, mid, &mdir) => 0;
for (mdir.mid.rid = 0; for (; (mdir.mid & lfsr_mridmask(&lfs))
mdir.mid.rid < (lfs_ssize_t)mdir.u.m.weight; < (lfs_ssize_t)mdir.u.m.weight;
mdir.mid.rid++) { mdir.mid += 1) {
uint8_t buffer[4]; uint8_t buffer[4];
lfsr_mdir_get(&lfs, &mdir, mdir.mid.rid, LFSR_TAG_REG, lfsr_mdir_get(&lfs, &mdir, mdir.mid, LFSR_TAG_REG,
buffer, 4) => 1; buffer, 4) => 1;
assert(memcmp(buffer, &alphas[i % 26], 1) == 0); assert(memcmp(buffer, &alphas[i % 26], 1) == 0);
i += 1; i += 1;
+428 -425
View File
File diff suppressed because it is too large Load Diff