WIP branches in dir

This commit is contained in:
Christopher Haster
2020-02-28 04:51:25 -06:00
parent 26ed6dee7d
commit f7bc22937a
2 changed files with 142 additions and 57 deletions

198
lfs.c
View File

@@ -789,6 +789,7 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
uint16_t tempcount = 0; uint16_t tempcount = 0;
lfs_block_t temptail[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL}; lfs_block_t temptail[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL};
lfs_block_t tempbranch[2] = {LFS_BLOCK_NULL, LFS_BLOCK_NULL};
bool tempsplit = false; bool tempsplit = false;
lfs_stag_t tempbesttag = besttag; lfs_stag_t tempbesttag = besttag;
@@ -861,6 +862,8 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
dir->count = tempcount; dir->count = tempcount;
dir->tail[0] = temptail[0]; dir->tail[0] = temptail[0];
dir->tail[1] = temptail[1]; dir->tail[1] = temptail[1];
dir->branch[0] = tempbranch[0];
dir->branch[1] = tempbranch[1];
dir->split = tempsplit; dir->split = tempsplit;
// reset crc // reset crc
@@ -914,6 +917,28 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs,
} }
} }
lfs_pair_fromle32(temptail); lfs_pair_fromle32(temptail);
// TODO hm
if (tempsplit) {
tempbranch[0] = temptail[0];
tempbranch[1] = temptail[1];
}
} else if (lfs_tag_type3(tag) == LFS_TYPE_BRANCH) {
if (lfs_tag_isdelete(tag)) {
tempbranch[0] = LFS_BLOCK_NULL;
tempbranch[1] = LFS_BLOCK_NULL;
} else {
// TODO endianness
err = lfs_bd_read(lfs,
NULL, &lfs->rcache, lfs->cfg->block_size,
dir->pair[0], off+sizeof(tag), &tempbranch, 8);
if (err) {
if (err == LFS_ERR_CORRUPT) {
dir->erased = false;
break;
}
}
}
} }
// found a match for our fetcher? // found a match for our fetcher?
@@ -1165,6 +1190,8 @@ nextname:
npair[0] = dir->tail[0]; npair[0] = dir->tail[0];
npair[1] = dir->tail[1]; npair[1] = dir->tail[1];
if (!dir->split) { if (!dir->split) {
// npair[0] = dir->branch[0];
// npair[1] = dir->branch[1];
ttag = lfs_dir_get(lfs, dir, ttag = lfs_dir_get(lfs, dir,
LFS_MKTAG(0x7ff, 0, 0), LFS_MKTAG(0x7ff, 0, 0),
LFS_MKTAG(LFS_TYPE_BRANCH, 0, sizeof(npair)), LFS_MKTAG(LFS_TYPE_BRANCH, 0, sizeof(npair)),
@@ -1173,6 +1200,7 @@ nextname:
return ttag; return ttag;
} }
lfs_pair_fromle32(npair); lfs_pair_fromle32(npair);
assert(ttag == LFS_ERR_NOENT || lfs_pair_cmp(npair, dir->branch) == 0);
} }
// ttag may be NOENT or may be marked null explicitly // ttag may be NOENT or may be marked null explicitly
@@ -1381,6 +1409,8 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir) {
dir->count = 0; dir->count = 0;
dir->tail[0] = LFS_BLOCK_NULL; dir->tail[0] = LFS_BLOCK_NULL;
dir->tail[1] = LFS_BLOCK_NULL; dir->tail[1] = LFS_BLOCK_NULL;
dir->branch[0] = LFS_BLOCK_NULL;
dir->branch[1] = LFS_BLOCK_NULL;
dir->erased = false; dir->erased = false;
dir->split = false; dir->split = false;
@@ -1481,15 +1511,20 @@ static int lfs_dir_split(lfs_t *lfs,
tail.split = dir->split; tail.split = dir->split;
tail.tail[0] = dir->tail[0]; tail.tail[0] = dir->tail[0];
tail.tail[1] = dir->tail[1]; tail.tail[1] = dir->tail[1];
tail.branch[0] = dir->branch[0];
tail.branch[1] = dir->branch[1];
err = lfs_dir_compact(lfs, &tail, attrs, attrcount, source, split, end); err = lfs_dir_compact(lfs, &tail, attrs, attrcount, source, split, end);
if (err) { if (err) {
return err; return err;
} }
dir->split = false;
dir->tail[0] = tail.pair[0]; dir->tail[0] = tail.pair[0];
dir->tail[1] = tail.pair[1]; dir->tail[1] = tail.pair[1];
dir->split = true; dir->branch[0] = tail.pair[0];
dir->branch[1] = tail.pair[1];
//dir->split = true;
// update root if needed // update root if needed
if (lfs_pair_cmp(dir->pair, lfs->root) == 0 && split == 0) { if (lfs_pair_cmp(dir->pair, lfs->root) == 0 && split == 0) {
@@ -1685,36 +1720,68 @@ static int lfs_dir_compact(lfs_t *lfs,
return err; return err;
} }
// Also commit branch or turn branch+tail into explicit branch if (dir->split) {
// and tail. This helps handling of relocations. You may wonder dir->branch[0] = dir->tail[0];
// why we even have the branch+tail type, and that is simply dir->branch[1] = dir->tail[1];
// because of backwards compatibility.
//
// Note we don't need to convert to/from le32 because we commit
// it straight to disk
lfs_stag_t btag = 0;
lfs_block_t bpair[2] = {dir->tail[0], dir->tail[1]};
if (!dir->split) {
btag = lfs_dir_get(lfs, source,
LFS_MKTAG(0x7ff, 0, 0),
LFS_MKTAG(LFS_TYPE_BRANCH, 0, sizeof(bpair)),
bpair);
if (btag < 0 && btag != LFS_ERR_NOENT) {
return btag;
}
} }
if (btag != LFS_ERR_NOENT) { // // Also commit branch or turn branch+tail into explicit branch
err = lfs_dir_commitattr(lfs, &commit, // // and tail. This helps handling of relocations. You may wonder
LFS_MKTAG(LFS_TYPE_BRANCH, 0x3ff, 8), // // why we even have the branch+tail type, and that is simply
bpair); // // because of backwards compatibility.
if (err) { // //
if (err == LFS_ERR_CORRUPT) { // // Note we don't need to convert to/from le32 because we commit
goto relocate; // // it straight to disk
} // lfs_stag_t btag = 0;
return err; // lfs_block_t bpair[2] = {dir->tail[0], dir->tail[1]};
// if (!dir->split) {
// btag = lfs_dir_get(lfs, source,
// LFS_MKTAG(0x7ff, 0, 0),
// LFS_MKTAG(LFS_TYPE_BRANCH, 0, sizeof(bpair)),
// bpair);
// if (btag < 0 && btag != LFS_ERR_NOENT) {
// return btag;
// }
// }
//
// if (btag != LFS_ERR_NOENT) {
// err = lfs_dir_commitattr(lfs, &commit,
// LFS_MKTAG(LFS_TYPE_BRANCH, 0x3ff, 8),
// bpair);
// if (err) {
// if (err == LFS_ERR_CORRUPT) {
// goto relocate;
// }
// return err;
// }
// }
}
// TODO comment these
// commit branch
if (!lfs_pair_isnull(dir->branch)) {
LFS_ASSERT(dir->branch[0] < lfs->cfg->block_count &&
dir->branch[1] < lfs->cfg->block_count);
err = lfs_dir_commitattr(lfs, &commit,
LFS_MKTAG(LFS_TYPE_BRANCH, 0x3ff, 8),
dir->branch);
if (err) {
if (err == LFS_ERR_CORRUPT) {
goto relocate;
} }
return err;
} }
// } else if (dir->split && !lfs_pair_isnull(dir->tail)) {
// // commit branch from tail?
// err = lfs_dir_commitattr(lfs, &commit,
// LFS_MKTAG(LFS_TYPE_BRANCH, 0x3ff, 8),
// dir->tail);
// if (err) {
// if (err == LFS_ERR_CORRUPT) {
// goto relocate;
// }
// return err;
// }
} }
// bring over gstate? // bring over gstate?
@@ -1910,6 +1977,20 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir,
dir->tail[1] = ((lfs_block_t*)attrs[i].buffer)[1]; dir->tail[1] = ((lfs_block_t*)attrs[i].buffer)[1];
dir->split = (lfs_tag_chunk(attrs[i].tag) & 1); dir->split = (lfs_tag_chunk(attrs[i].tag) & 1);
lfs_pair_fromle32(dir->tail); lfs_pair_fromle32(dir->tail);
// TODO hm
if (dir->split) {
dir->branch[0] = dir->tail[0];
dir->branch[1] = dir->tail[1];
}
} else if (lfs_tag_type3(attrs[i].tag) == LFS_TYPE_BRANCH) {
if (lfs_tag_isdelete(attrs[i].tag)) {
dir->branch[0] = 0xffffffff;
dir->branch[1] = 0xffffffff;
} else {
dir->branch[0] = ((lfs_block_t*)attrs[i].buffer)[0];
dir->branch[1] = ((lfs_block_t*)attrs[i].buffer)[1];
// TODO endianness?
}
} }
} }
@@ -2077,30 +2158,32 @@ compact:
for (struct lfs_mlist *d = lfs->mlist; d; d = d->next) { for (struct lfs_mlist *d = lfs->mlist; d; d = d->next) {
if (lfs_pair_cmp(d->m.pair, olddir.pair) == 0) { if (lfs_pair_cmp(d->m.pair, olddir.pair) == 0) {
while (d->id >= d->m.count) { while (d->id >= d->m.count && !lfs_pair_isnull(d->m.branch)) {
// we split and id is on tail now //
// TODO should I make this a common function? //
// TODO use softtail? // // we split and id is on tail now
lfs_stag_t ttag = 0; // // TODO should I make this a common function?
lfs_block_t npair[2] = {d->m.tail[0], d->m.tail[1]}; // // TODO use softtail?
if (!d->m.split) { // lfs_stag_t ttag = 0;
ttag = lfs_dir_get(lfs, &d->m, // lfs_block_t npair[2] = {d->m.tail[0], d->m.tail[1]};
LFS_MKTAG(0x7ff, 0, 0), // if (!d->m.split) {
LFS_MKTAG(LFS_TYPE_BRANCH, 0, sizeof(npair)), // ttag = lfs_dir_get(lfs, &d->m,
npair); // LFS_MKTAG(0x7ff, 0, 0),
if (ttag < 0 && ttag != LFS_ERR_NOENT) { // LFS_MKTAG(LFS_TYPE_BRANCH, 0, sizeof(npair)),
return ttag; // npair);
} // if (ttag < 0 && ttag != LFS_ERR_NOENT) {
lfs_pair_fromle32(npair); // return ttag;
} // }
// lfs_pair_fromle32(npair);
// ttag may be NOENT or may be marked null explicitly // }
if (ttag == LFS_ERR_NOENT || lfs_pair_isnull(npair)) { //
break; // // ttag may be NOENT or may be marked null explicitly
} // if (ttag == LFS_ERR_NOENT || lfs_pair_isnull(npair)) {
// break;
// }
d->id -= d->m.count; d->id -= d->m.count;
int err = lfs_dir_fetch(lfs, &d->m, npair); int err = lfs_dir_fetch(lfs, &d->m, d->m.branch);
if (err) { if (err) {
return err; return err;
} }
@@ -4422,14 +4505,6 @@ static int lfs_fs_deorphan(lfs_t *lfs) {
return tag; return tag;
} }
lfs_block_t pair[2];
lfs_stag_t res = lfs_dir_get(lfs, &parent,
LFS_MKTAG(0x7ff, 0x3ff, 0), tag, pair);
if (res < 0) {
return res;
}
lfs_pair_fromle32(pair);
// Half-orphans can also be true orphans if there is a better // Half-orphans can also be true orphans if there is a better
// child. Currently the child must be our successor. // child. Currently the child must be our successor.
if (tag == LFS_ERR_NOENT) { if (tag == LFS_ERR_NOENT) {
@@ -4450,7 +4525,16 @@ static int lfs_fs_deorphan(lfs_t *lfs) {
continue; continue;
} }
lfs_block_t pair[2];
lfs_stag_t res = lfs_dir_get(lfs, &parent,
LFS_MKTAG(0x7ff, 0x3ff, 0), tag, pair);
if (res < 0) {
return res;
}
lfs_pair_fromle32(pair);
if (!lfs_pair_sync(pair, pdir.tail)) { if (!lfs_pair_sync(pair, pdir.tail)) {
assert(false);
// we have desynced // we have desynced
LFS_DEBUG("Fixing half-orphan " LFS_DEBUG("Fixing half-orphan "
"%"PRIx32" %"PRIx32" -> %"PRIx32" %"PRIx32, "%"PRIx32" %"PRIx32" -> %"PRIx32" %"PRIx32,

1
lfs.h
View File

@@ -313,6 +313,7 @@ typedef struct lfs_mdir {
bool erased; bool erased;
bool split; bool split;
lfs_block_t tail[2]; lfs_block_t tail[2];
lfs_block_t branch[2];
} lfs_mdir_t; } lfs_mdir_t;
// littlefs directory type // littlefs directory type