Skip to content

Commit 7ad9700

Browse files
committed
Integrated findscan into fetch as a built in side effect
Now that littlefs's fetchwith operations have stabilized a bit, there's actually only a single fetchwith operation, the findscan function. Given that there's no need for the internal functions to be a forward compatible API, we can integrate the findscan behaviour directly into fetchwith and avoid the (annoyingly) costly generalization overhead. As an added benefit, we can easily add additional tag modifications during fetch, such as the synthetic moves needed to resolve in-flight move operations without disk modifications.
1 parent fe31f79 commit 7ad9700

File tree

1 file changed

+74
-131
lines changed

1 file changed

+74
-131
lines changed

lfs.c

Lines changed: 74 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -507,8 +507,11 @@ static int lfs_commit_commit(lfs_t *lfs,
507507
attr.u.dir, NULL);
508508
}
509509

510-
uint16_t id = lfs_tag_id(attr.tag) - commit->filter.begin;
511-
attr.tag = lfs_mktag(0, id, 0) | (attr.tag & 0xffc00fff);
510+
if (lfs_tag_id(attr.tag) != 0x3ff) {
511+
// TODO eh?
512+
uint16_t id = lfs_tag_id(attr.tag) - commit->filter.begin;
513+
attr.tag = lfs_mktag(0, id, 0) | (attr.tag & 0xffc00fff);
514+
}
512515

513516
// check if we fit
514517
lfs_size_t size = lfs_tag_size(attr.tag);
@@ -757,12 +760,14 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir,
757760
return 0;
758761
}
759762

760-
static int lfs_dir_fetchwith(lfs_t *lfs,
763+
static int lfs_dir_find(lfs_t *lfs,
761764
lfs_mdir_t *dir, const lfs_block_t pair[2],
762-
int (*cb)(lfs_t *lfs, void *data, lfs_mattr_t attr), void *data) {
765+
uint32_t findmask, lfs_tag_t findtag,
766+
const void *findbuffer, lfs_tag_t *foundtag) {
763767
dir->pair[0] = pair[0];
764768
dir->pair[1] = pair[1];
765769
dir->stop_at_commit = false;
770+
*foundtag = 0xffffffff;
766771

767772
// find the block with the most recent revision
768773
uint32_t rev[2];
@@ -794,12 +799,14 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
794799
lfs_crc(&crc, &dir->rev, sizeof(dir->rev));
795800
dir->rev = lfs_fromle32(dir->rev);
796801

797-
lfs_mdir_t temp = *dir;
802+
lfs_mdir_t tempdir = *dir;
803+
lfs_tag_t tempfoundtag = *foundtag;
798804

799805
while (true) {
800806
// extract next tag
801807
lfs_tag_t tag;
802-
int err = lfs_bd_read(lfs, temp.pair[0], off, &tag, sizeof(tag));
808+
int err = lfs_bd_read(lfs, tempdir.pair[0],
809+
off, &tag, sizeof(tag));
803810
if (err) {
804811
return err;
805812
}
@@ -809,113 +816,84 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
809816

810817
// next commit not yet programmed
811818
if (lfs_tag_type(ptag) == LFS_TYPE_CRC && !lfs_tag_isvalid(tag)) {
812-
// synthetic move
813-
if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0
814-
&& cb) {
815-
int err = cb(lfs, data, (lfs_mattr_t){
816-
lfs_mktag(LFS_TYPE_DELETE,
817-
lfs->globals.move.id, 0)});
818-
if (err) {
819-
return err;
820-
}
821-
}
822-
823819
dir->erased = true;
824-
return 0;
820+
goto done;
825821
}
826822

827823
// check we're in valid range
828824
if (off + sizeof(tag)+lfs_tag_size(tag) > lfs->cfg->block_size) {
829825
break;
830826
}
831827

832-
//printf("tag r %#010x (%x:%x %03x %03x %03x)\n", tag, temp.pair[0], off+sizeof(tag), lfs_tag_type(tag), lfs_tag_id(tag), lfs_tag_size(tag));
833828
if (lfs_tag_type(tag) == LFS_TYPE_CRC) {
834829
// check the crc attr
835830
uint32_t dcrc;
836-
int err = lfs_bd_read(lfs, temp.pair[0],
831+
int err = lfs_bd_read(lfs, tempdir.pair[0],
837832
off+sizeof(tag), &dcrc, sizeof(dcrc));
838833
if (err) {
839834
return err;
840835
}
841836

842837
if (crc != lfs_fromle32(dcrc)) {
843-
if (off == sizeof(temp.rev)) {
838+
if (off == sizeof(tempdir.rev)) {
844839
// try other block
845840
break;
846841
} else {
847-
// snythetic move
848-
// TODO combine with above?
849-
if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0
850-
&& cb) {
851-
int err = cb(lfs, data, (lfs_mattr_t){
852-
lfs_mktag(LFS_TYPE_DELETE,
853-
lfs->globals.move.id, 0)});
854-
if (err) {
855-
return err;
856-
}
857-
}
858-
859842
// consider what we have good enough
860843
dir->erased = false;
861-
return 0;
844+
goto done;
862845
}
863846
}
864847

865-
temp.off = off + sizeof(tag)+lfs_tag_size(tag);
866-
temp.etag = tag;
848+
tempdir.off = off + sizeof(tag)+lfs_tag_size(tag);
849+
tempdir.etag = tag;
867850
crc = 0xffffffff;
868-
*dir = temp;
869-
870-
// TODO simplify this?
871-
if (cb) {
872-
err = cb(lfs, data, (lfs_mattr_t){
873-
(tag | 0x80000000),
874-
.u.d.block=temp.pair[0],
875-
.u.d.off=off+sizeof(tag)});
876-
if (err) {
877-
return err;
878-
}
879-
}
851+
*dir = tempdir;
852+
*foundtag = tempfoundtag;
880853
} else {
881-
// TODO crc before callback???
882-
err = lfs_bd_crc(lfs, temp.pair[0],
854+
err = lfs_bd_crc(lfs, tempdir.pair[0],
883855
off+sizeof(tag), lfs_tag_size(tag), &crc);
884856
if (err) {
885857
return err;
886858
}
887859

860+
if (lfs_tag_id(tag) < 0x3ff &&
861+
lfs_tag_id(tag) >= tempdir.count) {
862+
tempdir.count = lfs_tag_id(tag)+1;
863+
}
864+
888865
if (lfs_tag_subtype(tag) == LFS_TYPE_TAIL) {
889-
temp.split = (lfs_tag_type(tag) & 1);
890-
err = lfs_bd_read(lfs, temp.pair[0], off+sizeof(tag),
891-
temp.tail, sizeof(temp.tail));
866+
tempdir.split = (lfs_tag_type(tag) & 1);
867+
err = lfs_bd_read(lfs, tempdir.pair[0], off+sizeof(tag),
868+
tempdir.tail, sizeof(tempdir.tail));
892869
if (err) {
893870
return err;
894871
}
895872
} else if (lfs_tag_type(tag) == LFS_TYPE_GLOBALS) {
896-
err = lfs_bd_read(lfs, temp.pair[0], off+sizeof(tag),
897-
&temp.globals, sizeof(temp.globals));
873+
err = lfs_bd_read(lfs, tempdir.pair[0], off+sizeof(tag),
874+
&tempdir.globals, sizeof(tempdir.globals));
898875
if (err) {
899876
return err;
900877
}
901-
} else {
902-
if (lfs_tag_id(tag) < 0x3ff &&
903-
lfs_tag_id(tag) >= temp.count) {
904-
temp.count = lfs_tag_id(tag)+1;
878+
} else if (lfs_tag_type(tag) == LFS_TYPE_DELETE) {
879+
tempdir.count -= 1;
880+
881+
if (lfs_tag_id(tag) == lfs_tag_id(tempfoundtag)) {
882+
tempfoundtag = 0xffffffff;
883+
} else if (lfs_tag_id(tempfoundtag) < 0x3ff &&
884+
lfs_tag_id(tag) < lfs_tag_id(tempfoundtag)) {
885+
tempfoundtag -= lfs_mktag(0, 1, 0);
905886
}
906-
907-
if (lfs_tag_type(tag) == LFS_TYPE_DELETE) {
908-
temp.count -= 1;
887+
} else if ((tag & findmask) == (findtag & findmask)) {
888+
int res = lfs_bd_cmp(lfs, tempdir.pair[0], off+sizeof(tag),
889+
findbuffer, lfs_tag_size(tag));
890+
if (res < 0) {
891+
return res;
909892
}
910893

911-
if (cb) {
912-
err = cb(lfs, data, (lfs_mattr_t){
913-
(tag | 0x80000000),
914-
.u.d.block=temp.pair[0],
915-
.u.d.off=off+sizeof(tag)});
916-
if (err) {
917-
return err;
918-
}
894+
if (res) {
895+
// found a match
896+
tempfoundtag = tag;
919897
}
920898
}
921899
}
@@ -931,11 +909,34 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
931909

932910
LFS_ERROR("Corrupted dir pair at %d %d", dir->pair[0], dir->pair[1]);
933911
return LFS_ERR_CORRUPT;
912+
913+
done:
914+
// synthetic move
915+
if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0) {
916+
if (lfs->globals.move.id == lfs_tag_id(*foundtag)) {
917+
*foundtag = 0xffffffff;
918+
} else if (lfs_tag_id(*foundtag) < 0x3ff &&
919+
lfs->globals.move.id < lfs_tag_id(*foundtag)) {
920+
*foundtag -= lfs_mktag(0, 1, 0);
921+
}
922+
}
923+
924+
if (*foundtag == 0xffffffff) {
925+
return LFS_ERR_NOENT;
926+
}
927+
928+
return 0;
934929
}
935930

936931
static int lfs_dir_fetch(lfs_t *lfs,
937932
lfs_mdir_t *dir, const lfs_block_t pair[2]) {
938-
return lfs_dir_fetchwith(lfs, dir, pair, NULL, NULL);
933+
int err = lfs_dir_find(lfs, dir, pair,
934+
0xffffffff, 0xffffffff, NULL, &(lfs_tag_t){0});
935+
if (err && err != LFS_ERR_NOENT) {
936+
return err;
937+
}
938+
939+
return 0;
939940
}
940941

941942
static int lfs_dir_traverse(lfs_t *lfs, lfs_mdir_t *dir,
@@ -1115,6 +1116,8 @@ static int lfs_dir_compact(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattrlist_t *list,
11151116
break;
11161117

11171118
split:
1119+
// TODO update dirs that get split here?
1120+
11181121
// commit no longer fits, need to split dir,
11191122
// drop caches and create tail
11201123
lfs->pcache.block = 0xffffffff;
@@ -1414,66 +1417,6 @@ static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir,
14141417
return 0;
14151418
}
14161419

1417-
struct lfs_dir_find {
1418-
uint32_t mask;
1419-
lfs_tag_t tag;
1420-
const void *buffer;
1421-
lfs_tag_t foundtag;
1422-
lfs_tag_t temptag;
1423-
};
1424-
1425-
static int lfs_dir_findscan(lfs_t *lfs, void *p, lfs_mattr_t attr) {
1426-
struct lfs_dir_find *find = p;
1427-
1428-
if ((attr.tag & find->mask) == (find->tag & find->mask)) {
1429-
int res = lfs_bd_cmp(lfs, attr.u.d.block, attr.u.d.off,
1430-
find->buffer, lfs_tag_size(attr.tag));
1431-
if (res < 0) {
1432-
return res;
1433-
}
1434-
1435-
if (res) {
1436-
// found a match
1437-
find->temptag = attr.tag;
1438-
}
1439-
} else if (lfs_tag_type(attr.tag) == LFS_TYPE_DELETE) {
1440-
if (lfs_tag_id(attr.tag) == lfs_tag_id(find->temptag)) {
1441-
find->temptag = 0xffffffff;
1442-
} else if (lfs_tag_id(find->temptag) < 0x3ff &&
1443-
lfs_tag_id(attr.tag) < lfs_tag_id(find->temptag)) {
1444-
find->temptag -= lfs_mktag(0, 1, 0);
1445-
}
1446-
} else if (lfs_tag_type(attr.tag) == LFS_TYPE_CRC) {
1447-
find->foundtag = find->temptag;
1448-
}
1449-
1450-
return 0;
1451-
}
1452-
1453-
static int lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir, const lfs_block_t *pair,
1454-
uint32_t mask, lfs_tag_t tag,
1455-
const void *buffer, lfs_tag_t *foundtag) {
1456-
struct lfs_dir_find find = {
1457-
.mask = mask,
1458-
.tag = tag,
1459-
.buffer = buffer,
1460-
.foundtag = 0xffffffff,
1461-
.temptag = 0xffffffff,
1462-
};
1463-
1464-
int err = lfs_dir_fetchwith(lfs, dir, pair, lfs_dir_findscan, &find);
1465-
if (err) {
1466-
return err;
1467-
}
1468-
1469-
if (find.foundtag == 0xffffffff) {
1470-
return LFS_ERR_NOENT;
1471-
}
1472-
1473-
*foundtag = find.foundtag;
1474-
return 0;
1475-
}
1476-
14771420

14781421
// TODO drop others, make this only return id, also make get take in only entry to populate (with embedded tag)
14791422
static int lfs_dir_lookup(lfs_t *lfs, lfs_mdir_t *dir,

0 commit comments

Comments
 (0)