mirror of
https://github.com/eledio-devices/thirdparty-littlefs.git
synced 2025-11-01 00:38:29 +01:00
WIP TEMP move work
This commit is contained in:
188
lfs.c
188
lfs.c
@@ -624,7 +624,7 @@ struct lfs_commit_move {
|
||||
|
||||
|
||||
// TODO redeclare
|
||||
static int lfs_mdir_traverse(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
static int lfs_dir_traverse(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
int (*cb)(lfs_t *lfs, void *data, lfs_mattr_t attr),
|
||||
void *data);
|
||||
static int lfs_dir_get(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
@@ -692,7 +692,7 @@ static int lfs_commit_move(lfs_t *lfs, struct lfs_commit *commit,
|
||||
}
|
||||
}
|
||||
|
||||
int err = lfs_mdir_traverse(lfs, dir, lfs_commit_movescan, &move);
|
||||
int err = lfs_dir_traverse(lfs, dir, lfs_commit_movescan, &move);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@@ -726,6 +726,7 @@ static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
dir->tail[1] = tail[1];
|
||||
dir->erased = false;
|
||||
dir->split = split;
|
||||
dir->idelete = (lfs_entry_t){{0, 0}, 0};
|
||||
|
||||
// don't write out yet, let caller take care of that
|
||||
return 0;
|
||||
@@ -762,6 +763,7 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
|
||||
dir->tail[1] = 0xffffffff;
|
||||
dir->count = 0;
|
||||
dir->split = false;
|
||||
dir->idelete = (lfs_entry_t){{0, 0}, 0};
|
||||
dir->moveid = -1;
|
||||
|
||||
dir->rev = lfs_tole32(rev[0]);
|
||||
@@ -783,6 +785,14 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
|
||||
|
||||
// next commit not yet programmed
|
||||
if (lfs_tag_type(ptag) == LFS_TYPE_CRC && !lfs_tag_valid(tag)) {
|
||||
if (lfs_paircmp(dir->pair, lfs->idelete.pair) == 0 && cb) {
|
||||
int err = cb(lfs, data, (lfs_mattr_t){
|
||||
lfs_mktag(LFS_TYPE_DELETE, lfs->idelete.id, 0)});
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
dir->erased = true;
|
||||
return 0;
|
||||
}
|
||||
@@ -807,6 +817,17 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
|
||||
// try other block
|
||||
break;
|
||||
} else {
|
||||
// TODO combine with above?
|
||||
if (lfs_paircmp(dir->pair, lfs->idelete.pair) == 0
|
||||
&& cb) {
|
||||
int err = cb(lfs, data, (lfs_mattr_t){
|
||||
lfs_mktag(LFS_TYPE_DELETE,
|
||||
lfs->idelete.id, 0)});
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// consider what we have good enough
|
||||
dir->erased = false;
|
||||
return 0;
|
||||
@@ -818,6 +839,7 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
|
||||
crc = 0xffffffff;
|
||||
*dir = temp;
|
||||
} else {
|
||||
// TODO crc before callback???
|
||||
err = lfs_bd_crc(lfs, temp.pair[0],
|
||||
off+sizeof(tag), lfs_tag_size(tag), &crc);
|
||||
if (err) {
|
||||
@@ -832,6 +854,12 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
} else if (lfs_tag_type(tag) == LFS_TYPE_IDELETE) {
|
||||
err = lfs_bd_read(lfs, temp.pair[0], off+sizeof(tag),
|
||||
&temp.idelete, sizeof(temp.idelete));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
} else if (lfs_tag_type(tag) == LFS_TYPE_MOVE) {
|
||||
// TODO handle moves correctly?
|
||||
temp.moveid = lfs_tag_id(tag);
|
||||
@@ -883,22 +911,31 @@ static int lfs_dir_fetch(lfs_t *lfs,
|
||||
return lfs_dir_fetchwith(lfs, dir, pair, NULL, NULL);
|
||||
}
|
||||
|
||||
static int lfs_mdir_traverse(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
static int lfs_dir_traverse(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
int (*cb)(lfs_t *lfs, void *data, lfs_mattr_t attr), void *data) {
|
||||
// iterate over dir block backwards (for faster lookups)
|
||||
lfs_block_t block = dir->pair[0];
|
||||
lfs_off_t off = dir->off;
|
||||
lfs_tag_t tag = dir->etag;
|
||||
|
||||
if (lfs_paircmp(dir->pair, lfs->idelete.pair) == 0) {
|
||||
int err = cb(lfs, data, (lfs_mattr_t){
|
||||
lfs_mktag(LFS_TYPE_DELETE, lfs->idelete.id, 0)});
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
while (off != sizeof(uint32_t)) {
|
||||
// TODO rm me
|
||||
//printf("tag r %#010x (%x:%x %03x %03x %03x)\n", tag, block, off-lfs_tag_size(tag), lfs_tag_type(tag), lfs_tag_id(tag), lfs_tag_size(tag));
|
||||
|
||||
// TODO hmm
|
||||
if (dir->stop_at_commit && lfs_tag_type(tag) == LFS_TYPE_CRC) {
|
||||
if (lfs_tag_type(tag) == LFS_TYPE_CRC) {
|
||||
if (dir->stop_at_commit) {
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
int err = cb(lfs, data, (lfs_mattr_t){
|
||||
(0x80000000 | tag),
|
||||
.u.d.block=block,
|
||||
@@ -906,12 +943,13 @@ static int lfs_mdir_traverse(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
LFS_ASSERT(off > sizeof(tag)+lfs_tag_size(tag));
|
||||
off -= sizeof(tag)+lfs_tag_size(tag);
|
||||
|
||||
lfs_tag_t ntag;
|
||||
err = lfs_bd_read(lfs, block, off, &ntag, sizeof(ntag));
|
||||
int err = lfs_bd_read(lfs, block, off, &ntag, sizeof(ntag));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@@ -963,7 +1001,7 @@ static int lfs_dir_compact(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattrlist_t *list,
|
||||
.block = dir->pair[1],
|
||||
.off = sizeof(dir->rev),
|
||||
|
||||
// space is complicated, we need room for tail, crc,
|
||||
// space is complicated, we need room for tail, crc, idelete,
|
||||
// and we keep cap at around half a block
|
||||
.begin = 0,
|
||||
.end = lfs_min(
|
||||
@@ -1008,6 +1046,22 @@ static int lfs_dir_compact(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattrlist_t *list,
|
||||
}
|
||||
}
|
||||
|
||||
if (!(dir->idelete.pair[0] == 0 &&
|
||||
dir->idelete.pair[0] == 0 &&
|
||||
dir->idelete.id == 0)) {
|
||||
// TODO le32
|
||||
err = lfs_commit_commit(lfs, &commit, (lfs_mattr_t){
|
||||
lfs_mktag(LFS_TYPE_IDELETE,
|
||||
0x1ff, sizeof(dir->idelete)),
|
||||
.u.buffer=&dir->idelete});
|
||||
if (err) {
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
goto relocate;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = lfs_commit_crc(lfs, &commit);
|
||||
if (err) {
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
@@ -1130,7 +1184,6 @@ compact:
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO combine with above?
|
||||
// update any directories that are affected
|
||||
for (lfs_dir_t *d = lfs->dirs; d; d = d->next) {
|
||||
if (lfs_paircmp(d->m.pair, dir->pair) == 0) {
|
||||
@@ -1176,9 +1229,7 @@ static int lfs_dir_delete(lfs_t *lfs, lfs_mdir_t *dir, uint16_t id) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// shift over any files that are affected
|
||||
// TODO move this to dir_commit?
|
||||
// TODO use entries???
|
||||
// shift over any dirs/files that are affected
|
||||
for (lfs_dir_t *d = lfs->dirs; d; d = d->next) {
|
||||
if (lfs_paircmp(d->m.pair, dir->pair) == 0) {
|
||||
if (d->id > id) {
|
||||
@@ -1202,14 +1253,14 @@ static int lfs_dir_delete(lfs_t *lfs, lfs_mdir_t *dir, uint16_t id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct lfs_dir_getter {
|
||||
struct lfs_dir_get {
|
||||
uint32_t mask;
|
||||
lfs_tag_t tag;
|
||||
lfs_mattr_t *attr;
|
||||
};
|
||||
|
||||
static int lfs_dir_getter(lfs_t *lfs, void *p, lfs_mattr_t attr) {
|
||||
struct lfs_dir_getter *get = p;
|
||||
static int lfs_dir_getscan(lfs_t *lfs, void *p, lfs_mattr_t attr) {
|
||||
struct lfs_dir_get *get = p;
|
||||
|
||||
if ((attr.tag & get->mask) == (get->tag & get->mask)) {
|
||||
*get->attr = attr;
|
||||
@@ -1226,8 +1277,8 @@ static int lfs_dir_getter(lfs_t *lfs, void *p, lfs_mattr_t attr) {
|
||||
static int lfs_dir_get(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
uint32_t mask, lfs_mattr_t *attr) {
|
||||
uint16_t id = lfs_tag_id(attr->tag);
|
||||
int res = lfs_mdir_traverse(lfs, dir, lfs_dir_getter,
|
||||
&(struct lfs_dir_getter){mask, attr->tag, attr});
|
||||
int res = lfs_dir_traverse(lfs, dir, lfs_dir_getscan,
|
||||
&(struct lfs_dir_get){mask, attr->tag, attr});
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
@@ -1325,14 +1376,14 @@ static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct lfs_dir_finder {
|
||||
struct lfs_dir_find {
|
||||
const char *name;
|
||||
uint16_t len;
|
||||
int16_t id;
|
||||
};
|
||||
|
||||
static int lfs_dir_finder(lfs_t *lfs, void *p, lfs_mattr_t attr) {
|
||||
struct lfs_dir_finder *find = p;
|
||||
static int lfs_dir_findscan(lfs_t *lfs, void *p, lfs_mattr_t attr) {
|
||||
struct lfs_dir_find *find = p;
|
||||
|
||||
if (lfs_tag_type(attr.tag) == LFS_TYPE_NAME &&
|
||||
lfs_tag_size(attr.tag) == find->len) {
|
||||
@@ -1365,7 +1416,7 @@ static int lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
.u.pair[1] = lfs->root[1],
|
||||
};
|
||||
|
||||
struct lfs_dir_finder find = {
|
||||
struct lfs_dir_find find = {
|
||||
.name = *path,
|
||||
};
|
||||
|
||||
@@ -1420,7 +1471,7 @@ static int lfs_dir_find(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
//printf("checking %d %d for %s\n", attr.u.pair[0], attr.u.pair[1], *path);
|
||||
find.id = -1;
|
||||
int err = lfs_dir_fetchwith(lfs, dir, attr.u.pair,
|
||||
lfs_dir_finder, &find);
|
||||
lfs_dir_findscan, &find);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@@ -2903,6 +2954,7 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
lfs->files = NULL;
|
||||
lfs->dirs = NULL;
|
||||
lfs->deorphaned = false;
|
||||
lfs->idelete = (lfs_entry_t){{0xffffffff, 0xffffffff}, 0xffff};
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -3260,36 +3312,100 @@ static int lfs_pred(lfs_t *lfs, const lfs_block_t dir[2], lfs_mdir_t *pdir) {
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
struct lfs_dir_parentscan {
|
||||
lfs_block_t pair[2];
|
||||
int16_t id;
|
||||
};
|
||||
|
||||
static int lfs_parentscan(lfs_t *lfs, void *p, lfs_mattr_t attr) {
|
||||
struct lfs_dir_parentscan *parentscan = p;
|
||||
|
||||
if ((lfs_tag_type(attr.tag) & 0x10f) == LFS_STRUCT_DIR) {
|
||||
int err = lfs_bd_read(lfs, attr.u.d.block, attr.u.d.off,
|
||||
&attr.u, sizeof(attr.u));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (lfs_paircmp(attr.u.pair, parentscan->pair) == 0) {
|
||||
// found a match
|
||||
parentscan->id = lfs_tag_id(attr.tag);
|
||||
}
|
||||
} else if (lfs_tag_type(attr.tag) == LFS_TYPE_DELETE) {
|
||||
if (lfs_tag_id(attr.tag) == parentscan->id) {
|
||||
parentscan->id = -1;
|
||||
} else if (lfs_tag_id(attr.tag) < parentscan->id) {
|
||||
parentscan->id -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lfs_parent(lfs_t *lfs, const lfs_block_t pair[2],
|
||||
lfs_mdir_t *parent, lfs_mattr_t *attr) {
|
||||
// iterate over all directory directory entries
|
||||
parent->tail[0] = 0;
|
||||
parent->tail[1] = 1;
|
||||
while (!lfs_pairisnull(parent->tail)) {
|
||||
int err = lfs_dir_fetch(lfs, parent, parent->tail);
|
||||
struct lfs_dir_parentscan parentscan = {
|
||||
.pair[0] = pair[0],
|
||||
.pair[1] = pair[1],
|
||||
.id = -1
|
||||
};
|
||||
|
||||
int err = lfs_dir_fetchwith(lfs, parent, parent->tail,
|
||||
lfs_parentscan, &parentscan);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// TODO make this O(n) by using fetchwith to match the pointers
|
||||
for (uint16_t id = 0; id < parent->count; id++) {
|
||||
if (parentscan.id != -1) {
|
||||
int err = lfs_dir_getentry(lfs, parent, 0x43dff000,
|
||||
lfs_mktag(LFS_STRUCT_DIR, id, 0), attr);
|
||||
lfs_mktag(LFS_STRUCT_DIR, parentscan.id, 0), attr);
|
||||
if (err) {
|
||||
if (err == LFS_ERR_NOENT) {
|
||||
continue;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
if (lfs_paircmp(attr->u.pair, pair) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
//
|
||||
//static int lfs_parent(lfs_t *lfs, const lfs_block_t pair[2],
|
||||
// lfs_mdir_t *parent, lfs_mattr_t *attr) {
|
||||
// // iterate over all directory directory entries
|
||||
// parent->tail[0] = 0;
|
||||
// parent->tail[1] = 1;
|
||||
// while (!lfs_pairisnull(parent->tail)) {
|
||||
// int err = lfs_dir_fetch(lfs, parent, parent->tail);
|
||||
// if (err) {
|
||||
// return err;
|
||||
// }
|
||||
//
|
||||
// // TODO make this O(n) by using fetchwith to match the pointers
|
||||
// for (uint16_t id = 0; id < parent->count; id++) {
|
||||
// int err = lfs_dir_getentry(lfs, parent, 0x43dff000,
|
||||
// lfs_mktag(LFS_STRUCT_DIR, id, 0), attr);
|
||||
// if (err) {
|
||||
// if (err == LFS_ERR_NOENT) {
|
||||
// continue;
|
||||
// }
|
||||
// return err;
|
||||
// }
|
||||
//
|
||||
// if (lfs_paircmp(attr->u.pair, pair) == 0) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return false;
|
||||
//}
|
||||
/*
|
||||
static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2],
|
||||
lfs_mdir_t *parent, lfs_mattr_t *attr) {
|
||||
@@ -3494,6 +3610,7 @@ int lfs_deorphan(lfs_t *lfs) {
|
||||
|
||||
lfs_mdir_t pdir = {.split = true};
|
||||
lfs_mdir_t dir = {.tail = {0, 1}};
|
||||
lfs_entry_t idelete = {{0xffffffff, 0xffffffff}, 0xffff};
|
||||
|
||||
// iterate over all directory directory entries
|
||||
while (!lfs_pairisnull(dir.tail)) {
|
||||
@@ -3502,6 +3619,11 @@ int lfs_deorphan(lfs_t *lfs) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// xor together indirect deletes
|
||||
idelete.pair[0] ^= dir.idelete.pair[0];
|
||||
idelete.pair[1] ^= dir.idelete.pair[1];
|
||||
idelete.id ^= dir.idelete.id;
|
||||
|
||||
// check head blocks for orphans
|
||||
if (!pdir.split) {
|
||||
// check if we have a parent
|
||||
@@ -3531,7 +3653,7 @@ int lfs_deorphan(lfs_t *lfs) {
|
||||
|
||||
if (!lfs_pairsync(attr.u.pair, pdir.tail)) {
|
||||
// we have desynced
|
||||
LFS_DEBUG("Found desync %d %d",
|
||||
LFS_DEBUG("Found half-orphan %d %d",
|
||||
attr.u.pair[0], attr.u.pair[1]);
|
||||
|
||||
pdir.tail[0] = attr.u.pair[0];
|
||||
@@ -3580,6 +3702,10 @@ int lfs_deorphan(lfs_t *lfs) {
|
||||
memcpy(&pdir, &dir, sizeof(pdir));
|
||||
}
|
||||
|
||||
// update littlefs with current move
|
||||
// TODO do this here? needs to be before reads also
|
||||
lfs->idelete = idelete;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
|
||||
39
lfs.h
39
lfs.h
@@ -102,9 +102,10 @@ enum lfs_type {
|
||||
// internally used types
|
||||
LFS_TYPE_NAME = 0x010,
|
||||
LFS_TYPE_MOVE = 0x080,
|
||||
LFS_TYPE_DELETE = 0x090,
|
||||
LFS_TYPE_DELETE = 0x020,
|
||||
|
||||
LFS_TYPE_SUPERBLOCK = 0x0a0,
|
||||
LFS_TYPE_SUPERBLOCK = 0x030,
|
||||
LFS_TYPE_IDELETE = 0x0b0,
|
||||
LFS_TYPE_SOFTTAIL = 0x0c0,
|
||||
LFS_TYPE_HARDTAIL = 0x0d0,
|
||||
LFS_TYPE_CRC = 0x0e0,
|
||||
@@ -285,6 +286,25 @@ typedef struct lfs_mattrlist {
|
||||
struct lfs_mattrlist *next;
|
||||
} lfs_mattrlist_t;
|
||||
|
||||
typedef struct lfs_entry {
|
||||
lfs_block_t pair[2];
|
||||
uint16_t id;
|
||||
} lfs_entry_t;
|
||||
|
||||
typedef struct lfs_mdir {
|
||||
lfs_block_t pair[2];
|
||||
lfs_block_t tail[2];
|
||||
uint32_t rev;
|
||||
lfs_off_t off;
|
||||
uint32_t etag;
|
||||
uint16_t count;
|
||||
bool erased;
|
||||
bool split;
|
||||
lfs_entry_t idelete;
|
||||
bool stop_at_commit; // TODO hmmm
|
||||
uint16_t moveid; // TODO rm me
|
||||
} lfs_mdir_t;
|
||||
|
||||
typedef struct lfs_cache {
|
||||
lfs_block_t block;
|
||||
lfs_off_t off;
|
||||
@@ -307,19 +327,6 @@ typedef struct lfs_file {
|
||||
lfs_mattrlist_t *attrs;
|
||||
} lfs_file_t;
|
||||
|
||||
typedef struct lfs_mdir {
|
||||
lfs_block_t pair[2];
|
||||
lfs_block_t tail[2];
|
||||
uint32_t rev;
|
||||
lfs_off_t off;
|
||||
uint32_t etag;
|
||||
uint16_t count;
|
||||
bool erased;
|
||||
bool split;
|
||||
bool stop_at_commit; // TODO hmmm
|
||||
int16_t moveid;
|
||||
} lfs_mdir_t;
|
||||
|
||||
typedef struct lfs_dir {
|
||||
struct lfs_dir *next;
|
||||
struct lfs_mdir m;
|
||||
@@ -363,6 +370,8 @@ typedef struct lfs {
|
||||
|
||||
lfs_free_t free;
|
||||
bool deorphaned;
|
||||
lfs_entry_t idelete;
|
||||
lfs_entry_t diff;
|
||||
|
||||
lfs_size_t inline_size;
|
||||
lfs_size_t attrs_size;
|
||||
|
||||
Reference in New Issue
Block a user