mirror of
https://gitee.com/openharmony/third_party_littlefs
synced 2024-11-23 14:59:50 +00:00
Switched back to simple deorphan-step on directory remove
Originally I tried to reuse the indirect delete to accomplish truely atomic directory removes, however this fell apart when it came to implementing directory removes as a side-effect of renames. A single indirect-delete simply can't handle renames with removes as a side effects. When copying an entry to its destination, we need to atomically delete both the old entry, and the source of our copy. We can't delete both with only a single indirect-delete. It is possible to accomplish this with two indirect-deletes, but this is such an uncommon case that it's really not worth supporting efficiently due to how expensive globals are. I also dropped indirect-deletes for normal directory removes. I may add it back later, but at the moment it's extra code cost for that's not traveled very often. As a result, restructured the indirect delete handling to be a bit more generic, now with a multipurpose lfs_globals_t struct instead of the delete specific lfs_entry_t struct. Also worked on integrating xored-globals, now with several primitive global operations to manage fetching/updating globals on disk.
This commit is contained in:
parent
3ffcedb95b
commit
cebf7aa0fe
364
lfs.c
364
lfs.c
@ -267,6 +267,8 @@ static int lfs_parent(lfs_t *lfs, const lfs_block_t dir[2],
|
||||
static int lfs_moved(lfs_t *lfs, lfs_mdir_t *fromdir, uint16_t fromid);
|
||||
static int lfs_relocate(lfs_t *lfs,
|
||||
const lfs_block_t oldpair[2], const lfs_block_t newpair[2]);
|
||||
int lfs_scan(lfs_t *lfs);
|
||||
int lfs_fixmove(lfs_t *lfs);
|
||||
int lfs_deorphan(lfs_t *lfs);
|
||||
|
||||
|
||||
@ -458,6 +460,22 @@ static inline lfs_size_t lfs_tag_size(lfs_tag_t tag) {
|
||||
return tag & 0x00000fff;
|
||||
}
|
||||
|
||||
// operations on globals
|
||||
static lfs_globals_t lfs_globals_xor(
|
||||
const lfs_globals_t *a, const lfs_globals_t *b) {
|
||||
lfs_globals_t res;
|
||||
res.move.pair[0] = a->move.pair[0] ^ b->move.pair[0];
|
||||
res.move.pair[1] = a->move.pair[1] ^ b->move.pair[1];
|
||||
res.move.id = a->move.id ^ b->move.id;
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool lfs_globals_iszero(const lfs_globals_t *a) {
|
||||
return (a->move.pair[0] == 0 && a->move.pair[1] == 0 && a->move.id == 0);
|
||||
}
|
||||
|
||||
|
||||
// commit logic
|
||||
struct lfs_commit {
|
||||
lfs_block_t block;
|
||||
lfs_off_t off;
|
||||
@ -701,6 +719,23 @@ static int lfs_commit_move(lfs_t *lfs, struct lfs_commit *commit,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lfs_commit_globals(lfs_t *lfs, struct lfs_commit *commit,
|
||||
const lfs_globals_t *source, const lfs_globals_t *diff) {
|
||||
lfs_globals_t res = lfs_globals_xor(source, diff);
|
||||
|
||||
if (!lfs_globals_iszero(&res)) {
|
||||
int err = lfs_commit_commit(lfs, commit, (lfs_mattr_t){
|
||||
lfs_mktag(LFS_TYPE_IDELETE,
|
||||
res.move.id, sizeof(res.move.pair)),
|
||||
.u.buffer=res.move.pair});
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
bool split, const lfs_block_t tail[2]) {
|
||||
// allocate pair of dir blocks (backwards, so we write to block 1 first)
|
||||
@ -727,7 +762,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};
|
||||
dir->globals = (lfs_globals_t){0};
|
||||
|
||||
// don't write out yet, let caller take care of that
|
||||
return 0;
|
||||
@ -764,7 +799,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->globals = (lfs_globals_t){0};
|
||||
dir->moveid = -1;
|
||||
|
||||
dir->rev = lfs_tole32(rev[0]);
|
||||
@ -786,9 +821,12 @@ 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) {
|
||||
// synthetic move
|
||||
if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0
|
||||
&& cb) {
|
||||
int err = cb(lfs, data, (lfs_mattr_t){
|
||||
lfs_mktag(LFS_STRUCT_DELETE, lfs->idelete.id, 0)});
|
||||
lfs_mktag(LFS_STRUCT_DELETE,
|
||||
lfs->globals.move.id, 0)});
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@ -818,12 +856,13 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
|
||||
// try other block
|
||||
break;
|
||||
} else {
|
||||
// snythetic move
|
||||
// TODO combine with above?
|
||||
if (lfs_paircmp(dir->pair, lfs->idelete.pair) == 0
|
||||
if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0
|
||||
&& cb) {
|
||||
int err = cb(lfs, data, (lfs_mattr_t){
|
||||
lfs_mktag(LFS_STRUCT_DELETE,
|
||||
lfs->idelete.id, 0)});
|
||||
lfs->globals.move.id, 0)});
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@ -855,8 +894,10 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
|
||||
return err;
|
||||
}
|
||||
} else if (lfs_tag_type(tag) == LFS_TYPE_IDELETE) {
|
||||
temp.globals.move.id = lfs_tag_id(tag);
|
||||
err = lfs_bd_read(lfs, temp.pair[0], off+sizeof(tag),
|
||||
&temp.idelete, sizeof(temp.idelete));
|
||||
&temp.globals.move.pair,
|
||||
sizeof(temp.globals.move.pair));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@ -864,7 +905,7 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
|
||||
// TODO handle moves correctly?
|
||||
temp.moveid = lfs_tag_id(tag);
|
||||
} else {
|
||||
if (lfs_tag_id(tag) < 0x3ff &&
|
||||
if (lfs_tag_scope(tag) <= LFS_SCOPE_ENTRY &&
|
||||
lfs_tag_id(tag) >= temp.count) {
|
||||
temp.count = lfs_tag_id(tag)+1;
|
||||
}
|
||||
@ -918,9 +959,10 @@ static int lfs_dir_traverse(lfs_t *lfs, lfs_mdir_t *dir,
|
||||
lfs_off_t off = dir->off;
|
||||
lfs_tag_t tag = dir->etag;
|
||||
|
||||
if (lfs_paircmp(dir->pair, lfs->idelete.pair) == 0) {
|
||||
// synthetic move
|
||||
if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0) {
|
||||
int err = cb(lfs, data, (lfs_mattr_t){
|
||||
lfs_mktag(LFS_STRUCT_DELETE, lfs->idelete.id, 0)});
|
||||
lfs_mktag(LFS_STRUCT_DELETE, lfs->globals.move.id, 0)});
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
@ -1031,29 +1073,29 @@ static int lfs_dir_compact(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattrlist_t *list,
|
||||
ack = id;
|
||||
}
|
||||
|
||||
// reopen the reserved space at the end
|
||||
// TODO can I just commit these first?
|
||||
commit.end = lfs->cfg->block_size - 2*sizeof(uint32_t);
|
||||
if (!lfs_pairisnull(dir->tail)) {
|
||||
// TODO le32
|
||||
err = lfs_commit_commit(lfs, &commit, (lfs_mattr_t){
|
||||
lfs_mktag(LFS_STRUCT_TAIL + dir->split*0x8,
|
||||
0x3ff, sizeof(dir->tail)),
|
||||
.u.buffer=dir->tail});
|
||||
|
||||
if (!relocated) {
|
||||
err = lfs_commit_globals(lfs, &commit,
|
||||
&dir->globals, &lfs->diff);
|
||||
if (err) {
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
if (err == LFS_ERR_NOSPC) {
|
||||
goto split;
|
||||
} else if (err == LFS_ERR_CORRUPT) {
|
||||
goto relocate;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(dir->idelete.pair[0] == 0 &&
|
||||
dir->idelete.pair[0] == 0 &&
|
||||
dir->idelete.id == 0)) {
|
||||
if (!lfs_pairisnull(dir->tail)) {
|
||||
// TODO le32
|
||||
err = lfs_commit_commit(lfs, &commit, (lfs_mattr_t){
|
||||
lfs_mktag(LFS_TYPE_IDELETE,
|
||||
0x3ff, sizeof(dir->idelete)),
|
||||
.u.buffer=&dir->idelete});
|
||||
lfs_mktag(LFS_STRUCT_TAIL + dir->split*0x8,
|
||||
0x3ff, sizeof(dir->tail)),
|
||||
.u.buffer=dir->tail});
|
||||
if (err) {
|
||||
if (err == LFS_ERR_CORRUPT) {
|
||||
goto relocate;
|
||||
@ -1131,6 +1173,9 @@ relocate:
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
lfs->globals = lfs_globals_xor(&lfs->globals, &lfs->diff);
|
||||
lfs->diff = (lfs_globals_t){0};
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1162,6 +1207,16 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattrlist_t *list) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!lfs_globals_iszero(&lfs->diff)) {
|
||||
err = lfs_commit_globals(lfs, &commit, &dir->globals, &lfs->diff);
|
||||
if (err) {
|
||||
if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) {
|
||||
goto compact;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = lfs_commit_crc(lfs, &commit);
|
||||
if (err) {
|
||||
if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) {
|
||||
@ -1173,6 +1228,8 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, lfs_mattrlist_t *list) {
|
||||
// successful commit, lets update dir
|
||||
dir->off = commit.off;
|
||||
dir->etag = commit.ptag;
|
||||
lfs->globals = lfs_globals_xor(&lfs->globals, &lfs->diff);
|
||||
lfs->diff = (lfs_globals_t){0};
|
||||
break;
|
||||
|
||||
compact:
|
||||
@ -1212,9 +1269,13 @@ static int lfs_dir_delete(lfs_t *lfs, lfs_mdir_t *dir, uint16_t id) {
|
||||
}
|
||||
|
||||
if (res && pdir.split) {
|
||||
// steal tail, and global state
|
||||
pdir.split = dir->split;
|
||||
pdir.tail[0] = dir->tail[0];
|
||||
pdir.tail[1] = dir->tail[1];
|
||||
lfs->diff = dir->globals;
|
||||
lfs->globals = lfs_globals_xor(&lfs->globals, &dir->globals);
|
||||
|
||||
int err = lfs_dir_commit(lfs, &pdir, &(lfs_mattrlist_t){
|
||||
{lfs_mktag(LFS_STRUCT_TAIL + pdir.split*0x8,
|
||||
0x3ff, sizeof(pdir.tail)),
|
||||
@ -2661,17 +2722,50 @@ int lfs_remove(lfs_t *lfs, const char *path) {
|
||||
return err;
|
||||
}
|
||||
|
||||
lfs_mdir_t dir;
|
||||
if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) {
|
||||
lfs_mdir_t dir;
|
||||
// must be empty before removal
|
||||
err = lfs_dir_fetch(lfs, &dir, attr.u.pair);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// TODO lfs_dir_empty?
|
||||
if (dir.count > 0 || dir.split) {
|
||||
return LFS_ERR_NOTEMPTY;
|
||||
}
|
||||
//
|
||||
// // unlink from tail chain and create move to fix
|
||||
// lfs->diff.move.pair[0] = cwd.pair[0] ^ lfs->globals.move.pair[0];
|
||||
// lfs->diff.move.pair[1] = cwd.pair[1] ^ lfs->globals.move.pair[1];
|
||||
// lfs->diff.move.id = id ^ lfs->globals.move.id;
|
||||
//
|
||||
// // xor over our child's global state
|
||||
// lfs->diff = lfs_globals_xor(&lfs->diff, &dir.globals);
|
||||
// lfs->globals = lfs_globals_xor(&lfs->globals, &dir.globals);
|
||||
//
|
||||
// // find pred and remove
|
||||
// // TODO handle dropped block?
|
||||
// lfs_mdir_t pred;
|
||||
// int res = lfs_pred(lfs, dir.pair, &pred);
|
||||
// if (res < 0) {
|
||||
// return res;
|
||||
// }
|
||||
//
|
||||
// LFS_ASSERT(res); // must have pred
|
||||
// pred.tail[0] = dir.tail[0];
|
||||
// pred.tail[1] = dir.tail[1];
|
||||
// err = lfs_dir_commit(lfs, &pred, &(lfs_mattrlist_t){
|
||||
// {lfs_mktag(LFS_TYPE_SOFTTAIL, 0x3ff, sizeof(pred.tail)),
|
||||
// .u.buffer=pred.tail}});
|
||||
// if (err) {
|
||||
// return err;
|
||||
// }
|
||||
//
|
||||
// // mark global state to clear move entry
|
||||
// lfs->diff.move.pair[0] = 0xffffffff ^ lfs->globals.move.pair[0];
|
||||
// lfs->diff.move.pair[1] = 0xffffffff ^ lfs->globals.move.pair[1];
|
||||
// lfs->diff.move.id = 0x3ff ^ lfs->globals.move.id;
|
||||
}
|
||||
|
||||
// delete the entry
|
||||
@ -2680,31 +2774,28 @@ int lfs_remove(lfs_t *lfs, const char *path) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// if we were a directory, find pred, replace tail
|
||||
// TODO can this just deorphan?
|
||||
if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) {
|
||||
err = lfs_deorphan(lfs);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// // if we were a directory, fix the move we just created
|
||||
// if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) {
|
||||
// int res = lfs_pred(lfs, dir.pair, &cwd);
|
||||
// if (res < 0) {
|
||||
// return res;
|
||||
// }
|
||||
//
|
||||
// LFS_ASSERT(res); // must have pred
|
||||
// cwd.tail[0] = dir.tail[0];
|
||||
// cwd.tail[1] = dir.tail[1];
|
||||
//
|
||||
// err = lfs_dir_commit(lfs, &cwd, NULL, 0);
|
||||
// err = lfs_deorphan(lfs);
|
||||
// if (err) {
|
||||
// return err;
|
||||
// }
|
||||
// }
|
||||
|
||||
if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) {
|
||||
int res = lfs_pred(lfs, dir.pair, &cwd);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
LFS_ASSERT(res); // must have pred
|
||||
cwd.tail[0] = dir.tail[0];
|
||||
cwd.tail[1] = dir.tail[1];
|
||||
err = lfs_dir_commit(lfs, &cwd, &(lfs_mattrlist_t){
|
||||
{lfs_mktag(LFS_TYPE_SOFTTAIL, 0x3ff, sizeof(cwd.tail)),
|
||||
.u.buffer=cwd.tail}});
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2741,8 +2832,10 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
||||
}
|
||||
|
||||
bool prevexists = (err != LFS_ERR_NOENT);
|
||||
bool samepair = (lfs_paircmp(oldcwd.pair, newcwd.pair) == 0);
|
||||
//bool samepair = (lfs_paircmp(oldcwd.pair, newcwd.pair) == 0);
|
||||
|
||||
lfs_mattr_t prevattr;
|
||||
lfs_mdir_t prevdir;
|
||||
if (prevexists) {
|
||||
// get prev entry, check that we have same type
|
||||
err = lfs_dir_getentry(lfs, &newcwd, 0x703ff000,
|
||||
@ -2756,7 +2849,6 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
||||
}
|
||||
|
||||
if (lfs_tag_subtype(prevattr.tag) == LFS_TYPE_DIR) {
|
||||
lfs_mdir_t prevdir;
|
||||
// must be empty before removal
|
||||
err = lfs_dir_fetch(lfs, &prevdir, prevattr.u.pair);
|
||||
if (err) {
|
||||
@ -2781,19 +2873,24 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
||||
}
|
||||
}
|
||||
|
||||
// mark as moving
|
||||
//printf("RENAME MOVE %d %d %d\n", oldcwd.pair[0], oldcwd.pair[1], oldid);
|
||||
err = lfs_dir_commit(lfs, &oldcwd, &(lfs_mattrlist_t){
|
||||
{lfs_mktag(LFS_STRUCT_MOVE, oldid, 0)}});
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (samepair) {
|
||||
// update pair if newcwd == oldcwd
|
||||
newcwd = oldcwd;
|
||||
}
|
||||
// create move to fix later
|
||||
lfs->diff.move.pair[0] = oldcwd.pair[0] ^ lfs->globals.move.pair[0];
|
||||
lfs->diff.move.pair[1] = oldcwd.pair[1] ^ lfs->globals.move.pair[1];
|
||||
lfs->diff.move.id = oldid ^ lfs->globals.move.id;
|
||||
|
||||
// // mark as moving
|
||||
// //printf("RENAME MOVE %d %d %d\n", oldcwd.pair[0], oldcwd.pair[1], oldid);
|
||||
// err = lfs_dir_commit(lfs, &oldcwd, &(lfs_mattrlist_t){
|
||||
// {lfs_mktag(LFS_STRUCT_MOVE, oldid, 0)}});
|
||||
// if (err) {
|
||||
// return err;
|
||||
// }
|
||||
//
|
||||
// if (samepair) {
|
||||
// // update pair if newcwd == oldcwd
|
||||
// newcwd = oldcwd;
|
||||
// }
|
||||
//
|
||||
// TODO check that all complaints are fixed
|
||||
// // move to new location
|
||||
// // TODO NAME?????
|
||||
@ -2813,6 +2910,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
||||
// return err;
|
||||
// }
|
||||
|
||||
// move over all attributes
|
||||
err = lfs_dir_commit(lfs, &newcwd, &(lfs_mattrlist_t){
|
||||
{lfs_mktag(LFS_STRUCT_NAME | lfs_tag_subtype(oldattr.tag),
|
||||
newid, strlen(newpath)),
|
||||
@ -2823,28 +2921,53 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (samepair) {
|
||||
// update pair if newcwd == oldcwd
|
||||
oldcwd = newcwd;
|
||||
}
|
||||
|
||||
// remove old entry
|
||||
//printf("RENAME DELETE %d %d %d\n", oldcwd.pair[0], oldcwd.pair[1], oldid);
|
||||
err = lfs_dir_delete(lfs, &oldcwd, oldid);
|
||||
// clean up after ourselves
|
||||
err = lfs_fixmove(lfs);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// if we were a directory, find pred, replace tail
|
||||
// TODO can this just deorphan?
|
||||
if (prevexists && lfs_tag_subtype(prevattr.tag) == LFS_TYPE_DIR) {
|
||||
err = lfs_deorphan(lfs);
|
||||
if (err) {
|
||||
return err;
|
||||
int res = lfs_pred(lfs, prevdir.pair, &newcwd);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
|
||||
LFS_ASSERT(res); // must have pred
|
||||
newcwd.tail[0] = prevdir.tail[0];
|
||||
newcwd.tail[1] = prevdir.tail[1];
|
||||
err = lfs_dir_commit(lfs, &newcwd, &(lfs_mattrlist_t){
|
||||
{lfs_mktag(LFS_TYPE_SOFTTAIL, 0x3ff, sizeof(newcwd.tail)),
|
||||
.u.buffer=newcwd.tail}});
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
// if (samepair) {
|
||||
// // update pair if newcwd == oldcwd
|
||||
// oldcwd = newcwd;
|
||||
// }
|
||||
//
|
||||
// err = fix
|
||||
//
|
||||
// // remove old entry
|
||||
// //printf("RENAME DELETE %d %d %d\n", oldcwd.pair[0], oldcwd.pair[1], oldid);
|
||||
// err = lfs_dir_delete(lfs, &oldcwd, oldid);
|
||||
// if (err) {
|
||||
// return err;
|
||||
// }
|
||||
//
|
||||
// // if we were a directory, find pred, replace tail
|
||||
// // TODO can this just deorphan?
|
||||
// if (prevexists && lfs_tag_subtype(prevattr.tag) == LFS_TYPE_DIR) {
|
||||
// err = lfs_deorphan(lfs);
|
||||
// if (err) {
|
||||
// return err;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
return 0;
|
||||
}
|
||||
|
||||
//int lfs_getattrs(lfs_t *lfs, const char *path,
|
||||
@ -2954,7 +3077,17 @@ 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};
|
||||
lfs->globals.move.pair[0] = 0xffffffff;
|
||||
lfs->globals.move.pair[1] = 0xffffffff;
|
||||
lfs->globals.move.id = 0x3ff;
|
||||
lfs->diff = (lfs_globals_t){0};
|
||||
|
||||
// scan for any global updates
|
||||
// TODO rm me? need to grab any inits
|
||||
int err = lfs_scan(lfs);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -3122,6 +3255,11 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) {
|
||||
lfs->root[0] = superblock.root[0];
|
||||
lfs->root[1] = superblock.root[1];
|
||||
|
||||
err = lfs_scan(lfs);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3601,15 +3739,13 @@ static int lfs_relocate(lfs_t *lfs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lfs_deorphan(lfs_t *lfs) {
|
||||
lfs->deorphaned = true;
|
||||
if (lfs_pairisnull(lfs->root)) {
|
||||
int lfs_scan(lfs_t *lfs) {
|
||||
if (lfs_pairisnull(lfs->root)) { // TODO rm me
|
||||
return 0;
|
||||
}
|
||||
|
||||
lfs_mdir_t pdir = {.split = true};
|
||||
lfs_mdir_t dir = {.tail = {0, 1}};
|
||||
lfs_entry_t idelete = {{0xffffffff, 0xffffffff}, 0xffff};
|
||||
lfs_globals_t globals = {{{0xffffffff, 0xffffffff}, 0x3ff}};
|
||||
|
||||
// iterate over all directory directory entries
|
||||
while (!lfs_pairisnull(dir.tail)) {
|
||||
@ -3619,9 +3755,71 @@ int lfs_deorphan(lfs_t *lfs) {
|
||||
}
|
||||
|
||||
// xor together indirect deletes
|
||||
idelete.pair[0] ^= dir.idelete.pair[0];
|
||||
idelete.pair[1] ^= dir.idelete.pair[1];
|
||||
idelete.id ^= dir.idelete.id;
|
||||
globals = lfs_globals_xor(&globals, &dir.globals);
|
||||
}
|
||||
|
||||
// update littlefs with globals
|
||||
lfs->globals = globals;
|
||||
lfs->diff = (lfs_globals_t){0};
|
||||
if (!lfs_pairisnull(lfs->globals.move.pair)) {
|
||||
LFS_DEBUG("Found move %d %d %d",
|
||||
lfs->globals.move.pair[0],
|
||||
lfs->globals.move.pair[1],
|
||||
lfs->globals.move.id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lfs_fixmove(lfs_t *lfs) {
|
||||
LFS_DEBUG("Fixing move %d %d %d", // TODO move to just deorphan
|
||||
lfs->globals.move.pair[0],
|
||||
lfs->globals.move.pair[1],
|
||||
lfs->globals.move.id);
|
||||
|
||||
// mark global state to clear move entry
|
||||
lfs->diff.move.pair[0] = 0xffffffff ^ lfs->globals.move.pair[0];
|
||||
lfs->diff.move.pair[1] = 0xffffffff ^ lfs->globals.move.pair[1];
|
||||
lfs->diff.move.id = 0x3ff ^ lfs->globals.move.id;
|
||||
|
||||
// fetch and delete the moved entry
|
||||
lfs_mdir_t movedir;
|
||||
int err = lfs_dir_fetch(lfs, &movedir, lfs->globals.move.pair);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = lfs_dir_delete(lfs, &movedir, lfs->globals.move.id);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lfs_deorphan(lfs_t *lfs) {
|
||||
lfs->deorphaned = true;
|
||||
if (lfs_pairisnull(lfs->root)) { // TODO rm me?
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Fix bad moves
|
||||
if (!lfs_pairisnull(lfs->globals.move.pair)) {
|
||||
int err = lfs_fixmove(lfs);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
lfs_mdir_t pdir = {.split = true};
|
||||
lfs_mdir_t dir = {.tail = {0, 1}};
|
||||
|
||||
// iterate over all directory directory entries
|
||||
while (!lfs_pairisnull(dir.tail)) {
|
||||
int err = lfs_dir_fetch(lfs, &dir, dir.tail);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// check head blocks for orphans
|
||||
if (!pdir.split) {
|
||||
@ -3671,7 +3869,7 @@ int lfs_deorphan(lfs_t *lfs) {
|
||||
}
|
||||
|
||||
// check entries for moves
|
||||
if (dir.moveid >= 0) {
|
||||
//if (dir.moveid >= 0) {
|
||||
// TODO moves and stuff
|
||||
// TODO need to load entry to find it
|
||||
// // found moved entry
|
||||
@ -3698,15 +3896,11 @@ int lfs_deorphan(lfs_t *lfs) {
|
||||
// return err;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
//}
|
||||
|
||||
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;
|
||||
}
|
||||
/*
|
||||
|
23
lfs.h
23
lfs.h
@ -129,7 +129,7 @@ enum lfs_type {
|
||||
// internal sources
|
||||
LFS_FROM_REGION = 0x000,
|
||||
LFS_FROM_DISK = 0x200,
|
||||
LFS_FROM_MOVE = 0x004,
|
||||
LFS_FROM_MOVE = 0x0ff,
|
||||
};
|
||||
|
||||
// File open flags
|
||||
@ -296,10 +296,17 @@ 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_entry {
|
||||
// lfs_block_t pair[2];
|
||||
// uint16_t id;
|
||||
//} lfs_entry_t;
|
||||
|
||||
typedef struct lfs_globals {
|
||||
struct lfs_move {
|
||||
lfs_block_t pair[2];
|
||||
uint16_t id;
|
||||
} move;
|
||||
} lfs_globals_t;
|
||||
|
||||
typedef struct lfs_mdir {
|
||||
lfs_block_t pair[2];
|
||||
@ -310,7 +317,7 @@ typedef struct lfs_mdir {
|
||||
uint16_t count;
|
||||
bool erased;
|
||||
bool split;
|
||||
lfs_entry_t idelete;
|
||||
lfs_globals_t globals;
|
||||
bool stop_at_commit; // TODO hmmm
|
||||
uint16_t moveid; // TODO rm me
|
||||
} lfs_mdir_t;
|
||||
@ -380,8 +387,8 @@ typedef struct lfs {
|
||||
|
||||
lfs_free_t free;
|
||||
bool deorphaned;
|
||||
lfs_entry_t idelete;
|
||||
lfs_entry_t diff;
|
||||
lfs_globals_t globals;
|
||||
lfs_globals_t diff;
|
||||
|
||||
lfs_size_t inline_size;
|
||||
lfs_size_t attrs_size;
|
||||
|
@ -59,7 +59,7 @@ tests/test.py << TEST
|
||||
lfs_rename(&lfs, "b/hello", "c/hello") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
TEST
|
||||
truncate -s-7 blocks/6
|
||||
truncate -s-11 blocks/6
|
||||
tests/test.py << TEST
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir[0], "b") => 0;
|
||||
@ -86,8 +86,8 @@ tests/test.py << TEST
|
||||
lfs_rename(&lfs, "c/hello", "d/hello") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
TEST
|
||||
truncate -s-7 blocks/8
|
||||
truncate -s-7 blocks/a
|
||||
truncate -s-11 blocks/8
|
||||
truncate -s-11 blocks/a
|
||||
tests/test.py << TEST
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir[0], "c") => 0;
|
||||
@ -108,6 +108,32 @@ tests/test.py << TEST
|
||||
lfs_unmount(&lfs) => 0;
|
||||
TEST
|
||||
|
||||
echo "--- Move file after corrupt ---"
|
||||
tests/test.py -s << TEST
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_rename(&lfs, "c/hello", "d/hello") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
TEST
|
||||
tests/test.py << TEST
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir[0], "c") => 0;
|
||||
lfs_dir_read(&lfs, &dir[0], &info) => 1;
|
||||
strcmp(info.name, ".") => 0;
|
||||
lfs_dir_read(&lfs, &dir[0], &info) => 1;
|
||||
strcmp(info.name, "..") => 0;
|
||||
lfs_dir_read(&lfs, &dir[0], &info) => 0;
|
||||
lfs_dir_close(&lfs, &dir[0]) => 0;
|
||||
lfs_dir_open(&lfs, &dir[0], "d") => 0;
|
||||
lfs_dir_read(&lfs, &dir[0], &info) => 1;
|
||||
strcmp(info.name, ".") => 0;
|
||||
lfs_dir_read(&lfs, &dir[0], &info) => 1;
|
||||
strcmp(info.name, "..") => 0;
|
||||
lfs_dir_read(&lfs, &dir[0], &info) => 1;
|
||||
strcmp(info.name, "hello") => 0;
|
||||
lfs_dir_read(&lfs, &dir[0], &info) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
TEST
|
||||
|
||||
echo "--- Move dir ---"
|
||||
tests/test.py << TEST
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
|
Loading…
Reference in New Issue
Block a user