From 168977ffad7081fe68f0399627ea1d002f5067b0 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Wed, 21 Dec 2022 19:54:44 -0600 Subject: [PATCH] Implemented lfs_rbyd_lookup Though maybe this should not require exact matches? --- lfs.c | 123 +++++++++++++++++-- tests/test_rbyd.toml | 281 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 344 insertions(+), 60 deletions(-) diff --git a/lfs.c b/lfs.c index 31e08793..ddab4f24 100644 --- a/lfs.c +++ b/lfs.c @@ -452,7 +452,7 @@ static inline bool lfs_rtag_isalt(lfs_rtag_t tag) { } static inline bool lfs_rtag_intree(lfs_rtag_t tag) { - return !(tag & 0x6); + return (tag & 0x6) != 0x2; } static inline uint8_t lfs_rtag_type1(lfs_rtag_t tag) { @@ -463,6 +463,10 @@ static inline uint8_t lfs_rtag_type2(lfs_rtag_t tag) { return (tag >> 7) & 0xff; } +static inline uint16_t lfs_rtag_type3(lfs_rtag_t tag) { + return tag & 0x7fff; +} + static inline uint16_t lfs_rtag_id(lfs_rtag_t tag) { return (tag >> 15) & 0xffff; } @@ -944,6 +948,7 @@ static int lfs_rbyd_fetch(lfs_t *lfs, } // found trunk of tree? + printf("%x: %08x => %d %d\n", off, tag, wastrunk, lfs_rtag_intree(tag)); if (!wastrunk && lfs_rtag_intree(tag)) { trunk = off; wastrunk = true; @@ -1025,6 +1030,7 @@ static int lfs_rbyd_fetch(lfs_t *lfs, lfs->seed = lfs_crc32c(lfs->seed, &crc, sizeof(uint32_t)); // save what we've found so far + printf("trunk => %x\n", trunk); rbyd->trunk = trunk; rbyd->noff = off; rbyd->crc = crc; @@ -1059,11 +1065,112 @@ static int lfs_rbyd_fetch(lfs_t *lfs, return 0; } -//static lfs_ssize_t lfs_rbyd_lookup(lfs_t *lfs, lfs_rbyd_t *rbyd, -// lfs_rtag_t tag, lfs_off_t *off, lfs_rtag_t *ntag) { -// // TODO -// return 0; +// TODO make these rtag functions? +static inline bool lfs_rbyd_follow(lfs_rtag_t alt, + lfs_rtag_t lo, lfs_rtag_t hi) { + if (lfs_rtag_islt(alt)) { + return lfs_rtag_weight(alt) > lo; + } else { + return lfs_rtag_weight(alt) > hi; + } +} + +static inline void lfs_rbyd_trim(lfs_rtag_t alt, + lfs_rtag_t *lo, lfs_rtag_t *hi) { + lfs_rtag_t lo_ = *lo; + lfs_rtag_t hi_ = *hi; + + if (lfs_rtag_islt(alt)) { + if (lfs_rbyd_follow(alt, lo_, hi_)) { + *hi = lfs_rtag_weight(alt)-1 - *lo; + } else { + *lo = *lo - lfs_rtag_weight(alt); + } + } else { + if (lfs_rbyd_follow(alt, lo_, hi_)) { + *lo = lfs_rtag_weight(alt)-1 - *hi; + } else { + *hi = *hi - lfs_rtag_weight(alt); + } + } +} + +//static inline void lfs_rbyd_trim(lfs_rtag_t alt, +// lfs_rtag_t *lo, lfs_rtag_t *hi) { +// if (lfs_rtag_islt(alt)) { +// *lo = *lo - lfs_rtag_weight(alt); +// } else { +// *hi = *hi - lfs_rtag_weight(alt); +// } //} +// +//static inline void lfs_rbyd_trimf(lfs_rtag_t alt, +// lfs_rtag_t *lo, lfs_rtag_t *hi) { +// if (lfs_rtag_islt(alt)) { +// *hi = lfs_rtag_weight(alt)-1 - *lo; +// } else { +// *lo = lfs_rtag_weight(alt)-1 - *hi; +// } +//} + +static lfs_ssize_t lfs_rbyd_lookup(lfs_t *lfs, const lfs_rbyd_t *rbyd, + lfs_rtag_t tag, lfs_off_t *off, lfs_rtag_t *ntag) { + // no trunk yet? + lfs_off_t branch = rbyd->trunk; + if (!branch) { + return LFS_ERR_NOENT; + } + + // weights for pruning + lfs_rtag_t lo = lfs_rtag_weight(tag); + lfs_rtag_t hi = (((lfs_rtag_t)rbyd->count << 12) + 0xff8)-1 + - lfs_rtag_weight(tag); + printf("lo, hi = (%x, %x)\n", lo, hi); + + // descend down tree, building alt pointers + while (true) { + lfs_rtag_t alt; + lfs_off_t jump; + lfs_ssize_t delta = lfs_rbyd_readtag(lfs, + &lfs->pcache, &lfs->rcache, lfs->cfg->block_size, + rbyd->block, branch, &alt, &jump, NULL); + if (delta < 0) { + return delta; + } + + // found an alt? + if (lfs_rtag_isalt(alt)) { + printf("follow %x (%x, %x)? => %d\n", alt, lo, hi, lfs_rbyd_follow(alt, lo, hi)); + if (lfs_rbyd_follow(alt, lo, hi)) { + lfs_rbyd_trim(alt, &lo, &hi); + branch = branch - jump; + } else { + lfs_rbyd_trim(alt, &lo, &hi); + branch += delta; + } + + // found end of tree? + } else { + // different tag => not found + if (lfs_rtag_type3(alt) != lfs_rtag_type3(tag)) { + return LFS_ERR_NOENT; + } + + // update with what we found + if (ntag) { + lfs_rtag_t ntag_ = tag + ((hi+1) << 3); + if (lfs_rtag_weight(ntag_) + == ((lfs_rtag_t)rbyd->count << 12) + 0xff8) { + ntag_ = 0; + } + *ntag = ntag_; + } + *off = branch; + return jump; + } + + } +} static int lfs_rbyd_prog(lfs_t *lfs, lfs_cache_t *pcache, lfs_cache_t *rcache, @@ -1276,13 +1383,13 @@ static int lfs_rbyd_commit(lfs_t *lfs, lfs_rbyd_t *rbyd, return delta; } - // make jump absolute - jump = branch - jump; - // found an alt? if (lfs_rtag_isalt(alt)) { LFS_ASSERT(false); // TODO + // make jump absolute + jump = branch - jump; + // // prune? // if (lfs_rtag_weight(alt) >= lo+hi+1) { // LFS_ASSERT(p_alts[0]); diff --git a/tests/test_rbyd.toml b/tests/test_rbyd.toml index be6ab6ed..199acc2c 100644 --- a/tests/test_rbyd.toml +++ b/tests/test_rbyd.toml @@ -8,7 +8,7 @@ code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; - lfs_rbyd_t rbyd = { + lfs_rbyd_t rbyd_init = { .block = 0, .trunk = 0, .noff = 0, @@ -19,36 +19,36 @@ code = ''' }; // try an empty commit - lfs_rbyd_t rbyd_ = rbyd; - lfs_bd_erase(&lfs, rbyd_.block) => 0; - lfs_rbyd_commit(&lfs, &rbyd_, NULL) => 0; - lfs_rbyd_fetch(&lfs, &rbyd_, rbyd.block, NULL) => 0; + lfs_rbyd_t rbyd = rbyd_init; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, NULL) => 0; + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; // commit with one attribute - rbyd_ = rbyd; - lfs_bd_erase(&lfs, rbyd_.block) => 0; - lfs_rbyd_commit(&lfs, &rbyd_, - LFS_MKRATTR(UATTR, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, NULL)) => 0; - lfs_rbyd_fetch(&lfs, &rbyd_, rbyd.block, NULL) => 0; + rbyd = rbyd_init; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, NULL)) => 0; + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; // commit with two attributes - rbyd_ = rbyd; - lfs_bd_erase(&lfs, rbyd_.block) => 0; - lfs_rbyd_commit(&lfs, &rbyd_, - LFS_MKRATTR(UATTR, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, - LFS_MKRATTR(UATTR, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, + rbyd = rbyd_init; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, + LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, NULL))) => 0; - lfs_rbyd_fetch(&lfs, &rbyd_, rbyd.block, NULL) => 0; + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; // // commit with three attributes -// rbyd_ = rbyd; -// lfs_bd_erase(&lfs, rbyd_.block) => 0; -// lfs_rbyd_commit(&lfs, &rbyd_, -// LFS_MKRATTR(UATTR, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, -// LFS_MKRATTR(UATTR, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, -// LFS_MKRATTR(UATTR, 3, 0, &(uint32_t){0xcccccccc}, 4, +// rbyd = rbyd_init; +// lfs_bd_erase(&lfs, rbyd.block) => 0; +// lfs_rbyd_commit(&lfs, &rbyd, +// LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, +// LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, +// LFS_MKRATTR(GSTATE, 3, 0, &(uint32_t){0xcccccccc}, 4, // NULL)))) => 0; -// lfs_rbyd_fetch(&lfs, &rbyd_, rbyd.block) => 0; +// lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block) => 0; // TODO more? ''' @@ -60,7 +60,7 @@ code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; - lfs_rbyd_t rbyd = { + lfs_rbyd_t rbyd_init = { .block = 0, .trunk = 0, .noff = 0, @@ -71,46 +71,223 @@ code = ''' }; // try an empty commit - lfs_rbyd_t rbyd_ = rbyd; - lfs_bd_erase(&lfs, rbyd_.block) => 0; - lfs_rbyd_commit(&lfs, &rbyd_, NULL) => 0; - lfs_rbyd_fetch(&lfs, &rbyd_, rbyd.block, NULL) => 0; + lfs_rbyd_t rbyd = rbyd_init; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, NULL) => 0; + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; // commit with one attribute - rbyd_ = rbyd; - lfs_bd_erase(&lfs, rbyd_.block) => 0; - lfs_rbyd_commit(&lfs, &rbyd_, NULL) => 0; - lfs_rbyd_commit(&lfs, &rbyd_, - LFS_MKRATTR(UATTR, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, NULL)) => 0; - lfs_rbyd_fetch(&lfs, &rbyd_, rbyd.block, NULL) => 0; + rbyd = rbyd_init; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, NULL) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, NULL)) => 0; + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; // commit with two attributes - rbyd_ = rbyd; - lfs_bd_erase(&lfs, rbyd_.block) => 0; - lfs_rbyd_commit(&lfs, &rbyd_, - LFS_MKRATTR(UATTR, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, NULL)) => 0; - lfs_rbyd_commit(&lfs, &rbyd_, - LFS_MKRATTR(UATTR, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, NULL)) => 0; - lfs_rbyd_fetch(&lfs, &rbyd_, rbyd.block, NULL) => 0; + rbyd = rbyd_init; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, NULL)) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, NULL)) => 0; + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; // // commit with three attributes -// rbyd_ = rbyd; -// lfs_bd_erase(&lfs, rbyd_.block) => 0; -// lfs_rbyd_commit(&lfs, &rbyd_, -// LFS_MKRATTR(UATTR, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, NULL)) => 0; -// lfs_rbyd_commit(&lfs, &rbyd_, -// LFS_MKRATTR(UATTR, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, NULL)) => 0; -// lfs_rbyd_commit(&lfs, &rbyd_, -// LFS_MKRATTR(UATTR, 3, 0, &(uint32_t){0xcccccccc}, 4, NULL)) => 0; -// lfs_rbyd_fetch(&lfs, &rbyd_, rbyd.block) => 0; +// rbyd = rbyd_init; +// lfs_bd_erase(&lfs, rbyd.block) => 0; +// lfs_rbyd_commit(&lfs, &rbyd, +// LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, NULL)) => 0; +// lfs_rbyd_commit(&lfs, &rbyd, +// LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, NULL)) => 0; +// lfs_rbyd_commit(&lfs, &rbyd, +// LFS_MKRATTR(GSTATE, 3, 0, &(uint32_t){0xcccccccc}, 4, NULL)) => 0; +// lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block) => 0; // TODO more? ''' +[cases.rbyd_commit_lookup] +in = 'lfs.c' +defines.ERASE_VALUE = [0xff, 0x00, 0x1b, -1] +code = ''' + lfs_t lfs; + lfs_init(&lfs, cfg) => 0; + lfs_rbyd_t rbyd_init = { + .block = 0, + .trunk = 0, + .noff = 0, + .rev = 1, + .crc = 0, + .count = 0, + .erased = true, + }; + + // try an empty commit + lfs_rbyd_t rbyd = rbyd_init; + lfs_rtag_t ntag; // TODO assert on ntag? + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, NULL) => 0; + + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 1, 0), &(lfs_off_t){0}, &ntag) => LFS_ERR_NOENT; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 1, 0), &(lfs_off_t){0}, &ntag) => LFS_ERR_NOENT; + + // commit with one attribute + rbyd = rbyd_init; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, NULL)) => 0; + + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 1, 0), &(lfs_off_t){0}, &ntag) => 4; + assert(ntag == 0); + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 2, 0), &(lfs_off_t){0}, &ntag) => LFS_ERR_NOENT; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 1, 0), &(lfs_off_t){0}, &ntag) => 4; + assert(ntag == 0); + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 2, 0), &(lfs_off_t){0}, &ntag) => LFS_ERR_NOENT; + + // commit with two attributes + rbyd = rbyd_init; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, + LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, + NULL))) => 0; + + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 1, 0), &(lfs_off_t){0}, &ntag) => 4; + assert(ntag == LFS_MKRTAG(GSTATE, 2, 0)); + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 2, 0), &(lfs_off_t){0}, &ntag) => 4; + assert(ntag == 0); + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 3, 0), &(lfs_off_t){0}, &ntag) => LFS_ERR_NOENT; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 1, 0), &(lfs_off_t){0}, &ntag) => 4; + assert(ntag == LFS_MKRTAG(GSTATE, 2, 0)); + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 2, 0), &(lfs_off_t){0}, &ntag) => 4; + assert(ntag == 0); + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 3, 0), &(lfs_off_t){0}, &ntag) => LFS_ERR_NOENT; + +// // commit with three attributes +// rbyd = rbyd_init; +// lfs_bd_erase(&lfs, rbyd.block) => 0; +// lfs_rbyd_commit(&lfs, &rbyd, +// LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, +// LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, +// LFS_MKRATTR(GSTATE, 3, 0, &(uint32_t){0xcccccccc}, 4, +// NULL)))) => 0; +// lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block) => 0; + + // TODO more? +''' + +# TODO we should make sure lookup always returns <= the requested tag, +# this may require fixing in lfs_rbyd_commit to make sure the weights lean +# one way +[cases.rbyd_multi_commit_lookup] +in = 'lfs.c' +defines.ERASE_VALUE = [0xff, 0x00, 0x1b, -1] +code = ''' + lfs_t lfs; + lfs_init(&lfs, cfg) => 0; + + lfs_rbyd_t rbyd_init = { + .block = 0, + .trunk = 0, + .noff = 0, + .rev = 1, + .crc = 0, + .count = 0, + .erased = true, + }; + + // try an empty commit + lfs_rbyd_t rbyd = rbyd_init; + lfs_rtag_t ntag; // TODO assert on ntag? + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, NULL) => 0; + + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 1, 0), &(lfs_off_t){0}, &ntag) => LFS_ERR_NOENT; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 1, 0), &(lfs_off_t){0}, &ntag) => LFS_ERR_NOENT; + + // commit with one attribute + rbyd = rbyd_init; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, NULL)) => 0; + + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 1, 0), &(lfs_off_t){0}, &ntag) => 4; + assert(ntag == 0); + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 2, 0), &(lfs_off_t){0}, &ntag) => LFS_ERR_NOENT; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 1, 0), &(lfs_off_t){0}, &ntag) => 4; + assert(ntag == 0); + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 2, 0), &(lfs_off_t){0}, &ntag) => LFS_ERR_NOENT; + + // commit with two attributes + rbyd = rbyd_init; + lfs_bd_erase(&lfs, rbyd.block) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, NULL)) => 0; + lfs_rbyd_commit(&lfs, &rbyd, + LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, NULL)) => 0; + + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 1, 0), &(lfs_off_t){0}, &ntag) => 4; + assert(ntag == LFS_MKRTAG(GSTATE, 2, 0)); + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 2, 0), &(lfs_off_t){0}, &ntag) => 4; + assert(ntag == 0); + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 3, 0), &(lfs_off_t){0}, &ntag) => LFS_ERR_NOENT; + + lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 1, 0), &(lfs_off_t){0}, &ntag) => 4; + assert(ntag == LFS_MKRTAG(GSTATE, 2, 0)); + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 2, 0), &(lfs_off_t){0}, &ntag) => 4; + assert(ntag == 0); + lfs_rbyd_lookup(&lfs, &rbyd, + LFS_MKRTAG(GSTATE, 3, 0), &(lfs_off_t){0}, &ntag) => LFS_ERR_NOENT; + +// // commit with three attributes +// rbyd = rbyd_init; +// lfs_bd_erase(&lfs, rbyd.block) => 0; +// lfs_rbyd_commit(&lfs, &rbyd, +// LFS_MKRATTR(GSTATE, 1, 0, &(uint32_t){0xaaaaaaaa}, 4, +// LFS_MKRATTR(GSTATE, 2, 0, &(uint32_t){0xbbbbbbbb}, 4, +// LFS_MKRATTR(GSTATE, 3, 0, &(uint32_t){0xcccccccc}, 4, +// NULL)))) => 0; +// lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block) => 0; + + // TODO more? +''' -# [cases.rbyd_commit_lookup] -# [cases.rbyd_multi_commit_lookup] # [cases.rbyd_commit_fetchmatch] # [cases.rbyd_multi_commit_fetchmatch] # [cases.rbyd_commit_traverse]