WIP switched back to deorphan for remove

Utilizing moves wouldn't have worked for rename anyways, and it requires
additional code for much less traveled code path (directory removes)
This commit is contained in:
Christopher Haster
2018-07-01 22:29:42 -05:00
parent ff13345e96
commit 5064cf82fd
3 changed files with 323 additions and 96 deletions

364
lfs.c
View File

@@ -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_moved(lfs_t *lfs, lfs_mdir_t *fromdir, uint16_t fromid);
static int lfs_relocate(lfs_t *lfs, static int lfs_relocate(lfs_t *lfs,
const lfs_block_t oldpair[2], const lfs_block_t newpair[2]); 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); 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; 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 { struct lfs_commit {
lfs_block_t block; lfs_block_t block;
lfs_off_t off; lfs_off_t off;
@@ -701,6 +719,23 @@ static int lfs_commit_move(lfs_t *lfs, struct lfs_commit *commit,
return 0; 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, static int lfs_dir_alloc(lfs_t *lfs, lfs_mdir_t *dir,
bool split, const lfs_block_t tail[2]) { bool split, const lfs_block_t tail[2]) {
// allocate pair of dir blocks (backwards, so we write to block 1 first) // 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->tail[1] = tail[1];
dir->erased = false; dir->erased = false;
dir->split = split; 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 // don't write out yet, let caller take care of that
return 0; return 0;
@@ -764,7 +799,7 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
dir->tail[1] = 0xffffffff; dir->tail[1] = 0xffffffff;
dir->count = 0; dir->count = 0;
dir->split = false; dir->split = false;
dir->idelete = (lfs_entry_t){{0, 0}, 0}; dir->globals = (lfs_globals_t){0};
dir->moveid = -1; dir->moveid = -1;
dir->rev = lfs_tole32(rev[0]); dir->rev = lfs_tole32(rev[0]);
@@ -786,9 +821,12 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
// next commit not yet programmed // next commit not yet programmed
if (lfs_tag_type(ptag) == LFS_TYPE_CRC && !lfs_tag_valid(tag)) { 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){ 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) { if (err) {
return err; return err;
} }
@@ -818,12 +856,13 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
// try other block // try other block
break; break;
} else { } else {
// snythetic move
// TODO combine with above? // TODO combine with above?
if (lfs_paircmp(dir->pair, lfs->idelete.pair) == 0 if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0
&& cb) { && cb) {
int err = cb(lfs, data, (lfs_mattr_t){ int err = cb(lfs, data, (lfs_mattr_t){
lfs_mktag(LFS_STRUCT_DELETE, lfs_mktag(LFS_STRUCT_DELETE,
lfs->idelete.id, 0)}); lfs->globals.move.id, 0)});
if (err) { if (err) {
return err; return err;
} }
@@ -855,8 +894,10 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
return err; return err;
} }
} else if (lfs_tag_type(tag) == LFS_TYPE_IDELETE) { } 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), 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) { if (err) {
return err; return err;
} }
@@ -864,7 +905,7 @@ static int lfs_dir_fetchwith(lfs_t *lfs,
// TODO handle moves correctly? // TODO handle moves correctly?
temp.moveid = lfs_tag_id(tag); temp.moveid = lfs_tag_id(tag);
} else { } else {
if (lfs_tag_id(tag) < 0x3ff && if (lfs_tag_scope(tag) <= LFS_SCOPE_ENTRY &&
lfs_tag_id(tag) >= temp.count) { lfs_tag_id(tag) >= temp.count) {
temp.count = lfs_tag_id(tag)+1; 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_off_t off = dir->off;
lfs_tag_t tag = dir->etag; 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){ 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) { if (err) {
return 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; 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); commit.end = lfs->cfg->block_size - 2*sizeof(uint32_t);
if (!lfs_pairisnull(dir->tail)) {
// TODO le32 if (!relocated) {
err = lfs_commit_commit(lfs, &commit, (lfs_mattr_t){ err = lfs_commit_globals(lfs, &commit,
lfs_mktag(LFS_STRUCT_TAIL + dir->split*0x8, &dir->globals, &lfs->diff);
0x3ff, sizeof(dir->tail)),
.u.buffer=dir->tail});
if (err) { if (err) {
if (err == LFS_ERR_CORRUPT) { if (err == LFS_ERR_NOSPC) {
goto split;
} else if (err == LFS_ERR_CORRUPT) {
goto relocate; goto relocate;
} }
return err; return err;
} }
} }
if (!(dir->idelete.pair[0] == 0 && if (!lfs_pairisnull(dir->tail)) {
dir->idelete.pair[0] == 0 &&
dir->idelete.id == 0)) {
// TODO le32 // TODO le32
err = lfs_commit_commit(lfs, &commit, (lfs_mattr_t){ err = lfs_commit_commit(lfs, &commit, (lfs_mattr_t){
lfs_mktag(LFS_TYPE_IDELETE, lfs_mktag(LFS_STRUCT_TAIL + dir->split*0x8,
0x3ff, sizeof(dir->idelete)), 0x3ff, sizeof(dir->tail)),
.u.buffer=&dir->idelete}); .u.buffer=dir->tail});
if (err) { if (err) {
if (err == LFS_ERR_CORRUPT) { if (err == LFS_ERR_CORRUPT) {
goto relocate; goto relocate;
@@ -1131,6 +1173,9 @@ relocate:
if (err) { if (err) {
return err; return err;
} }
} else {
lfs->globals = lfs_globals_xor(&lfs->globals, &lfs->diff);
lfs->diff = (lfs_globals_t){0};
} }
return 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; 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); err = lfs_commit_crc(lfs, &commit);
if (err) { if (err) {
if (err == LFS_ERR_NOSPC || err == LFS_ERR_CORRUPT) { 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 // successful commit, lets update dir
dir->off = commit.off; dir->off = commit.off;
dir->etag = commit.ptag; dir->etag = commit.ptag;
lfs->globals = lfs_globals_xor(&lfs->globals, &lfs->diff);
lfs->diff = (lfs_globals_t){0};
break; break;
compact: compact:
@@ -1212,9 +1269,13 @@ static int lfs_dir_delete(lfs_t *lfs, lfs_mdir_t *dir, uint16_t id) {
} }
if (res && pdir.split) { if (res && pdir.split) {
// steal tail, and global state
pdir.split = dir->split; pdir.split = dir->split;
pdir.tail[0] = dir->tail[0]; pdir.tail[0] = dir->tail[0];
pdir.tail[1] = dir->tail[1]; 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){ int err = lfs_dir_commit(lfs, &pdir, &(lfs_mattrlist_t){
{lfs_mktag(LFS_STRUCT_TAIL + pdir.split*0x8, {lfs_mktag(LFS_STRUCT_TAIL + pdir.split*0x8,
0x3ff, sizeof(pdir.tail)), 0x3ff, sizeof(pdir.tail)),
@@ -2661,17 +2722,50 @@ int lfs_remove(lfs_t *lfs, const char *path) {
return err; return err;
} }
lfs_mdir_t dir;
if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) { if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) {
lfs_mdir_t dir;
// must be empty before removal // must be empty before removal
err = lfs_dir_fetch(lfs, &dir, attr.u.pair); err = lfs_dir_fetch(lfs, &dir, attr.u.pair);
if (err) { if (err) {
return err; return err;
} }
// TODO lfs_dir_empty?
if (dir.count > 0 || dir.split) { if (dir.count > 0 || dir.split) {
return LFS_ERR_NOTEMPTY; 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 // delete the entry
@@ -2680,31 +2774,28 @@ int lfs_remove(lfs_t *lfs, const char *path) {
return err; return err;
} }
// if we were a directory, find pred, replace tail // // if we were a directory, fix the move we just created
// TODO can this just deorphan?
if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) {
err = lfs_deorphan(lfs);
if (err) {
return err;
}
}
// if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) { // if (lfs_tag_subtype(attr.tag) == LFS_TYPE_DIR) {
// int res = lfs_pred(lfs, dir.pair, &cwd); // err = lfs_deorphan(lfs);
// 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);
// if (err) { // if (err) {
// return 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; 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 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_mattr_t prevattr;
lfs_mdir_t prevdir;
if (prevexists) { if (prevexists) {
// get prev entry, check that we have same type // get prev entry, check that we have same type
err = lfs_dir_getentry(lfs, &newcwd, 0x703ff000, 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) { if (lfs_tag_subtype(prevattr.tag) == LFS_TYPE_DIR) {
lfs_mdir_t prevdir;
// must be empty before removal // must be empty before removal
err = lfs_dir_fetch(lfs, &prevdir, prevattr.u.pair); err = lfs_dir_fetch(lfs, &prevdir, prevattr.u.pair);
if (err) { if (err) {
@@ -2781,19 +2873,24 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
} }
} }
// mark as moving // create move to fix later
//printf("RENAME MOVE %d %d %d\n", oldcwd.pair[0], oldcwd.pair[1], oldid); lfs->diff.move.pair[0] = oldcwd.pair[0] ^ lfs->globals.move.pair[0];
err = lfs_dir_commit(lfs, &oldcwd, &(lfs_mattrlist_t){ lfs->diff.move.pair[1] = oldcwd.pair[1] ^ lfs->globals.move.pair[1];
{lfs_mktag(LFS_STRUCT_MOVE, oldid, 0)}}); lfs->diff.move.id = oldid ^ lfs->globals.move.id;
if (err) {
return err;
}
if (samepair) {
// update pair if newcwd == oldcwd
newcwd = oldcwd;
}
// // 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 // TODO check that all complaints are fixed
// // move to new location // // move to new location
// // TODO NAME????? // // TODO NAME?????
@@ -2813,6 +2910,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
// return err; // return err;
// } // }
// move over all attributes
err = lfs_dir_commit(lfs, &newcwd, &(lfs_mattrlist_t){ err = lfs_dir_commit(lfs, &newcwd, &(lfs_mattrlist_t){
{lfs_mktag(LFS_STRUCT_NAME | lfs_tag_subtype(oldattr.tag), {lfs_mktag(LFS_STRUCT_NAME | lfs_tag_subtype(oldattr.tag),
newid, strlen(newpath)), newid, strlen(newpath)),
@@ -2823,28 +2921,53 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) {
return err; return err;
} }
if (samepair) { // clean up after ourselves
// update pair if newcwd == oldcwd err = lfs_fixmove(lfs);
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);
if (err) { if (err) {
return 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) { if (prevexists && lfs_tag_subtype(prevattr.tag) == LFS_TYPE_DIR) {
err = lfs_deorphan(lfs); int res = lfs_pred(lfs, prevdir.pair, &newcwd);
if (err) { if (res < 0) {
return err; 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; 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, //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->files = NULL;
lfs->dirs = NULL; lfs->dirs = NULL;
lfs->deorphaned = false; 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; 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[0] = superblock.root[0];
lfs->root[1] = superblock.root[1]; lfs->root[1] = superblock.root[1];
err = lfs_scan(lfs);
if (err) {
return err;
}
return 0; return 0;
} }
@@ -3601,15 +3739,13 @@ static int lfs_relocate(lfs_t *lfs,
return 0; return 0;
} }
int lfs_deorphan(lfs_t *lfs) { int lfs_scan(lfs_t *lfs) {
lfs->deorphaned = true; if (lfs_pairisnull(lfs->root)) { // TODO rm me
if (lfs_pairisnull(lfs->root)) {
return 0; return 0;
} }
lfs_mdir_t pdir = {.split = true};
lfs_mdir_t dir = {.tail = {0, 1}}; 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 // iterate over all directory directory entries
while (!lfs_pairisnull(dir.tail)) { while (!lfs_pairisnull(dir.tail)) {
@@ -3619,9 +3755,71 @@ int lfs_deorphan(lfs_t *lfs) {
} }
// xor together indirect deletes // xor together indirect deletes
idelete.pair[0] ^= dir.idelete.pair[0]; globals = lfs_globals_xor(&globals, &dir.globals);
idelete.pair[1] ^= dir.idelete.pair[1]; }
idelete.id ^= dir.idelete.id;
// 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 // check head blocks for orphans
if (!pdir.split) { if (!pdir.split) {
@@ -3671,7 +3869,7 @@ int lfs_deorphan(lfs_t *lfs) {
} }
// check entries for moves // check entries for moves
if (dir.moveid >= 0) { //if (dir.moveid >= 0) {
// TODO moves and stuff // TODO moves and stuff
// TODO need to load entry to find it // TODO need to load entry to find it
// // found moved entry // // found moved entry
@@ -3698,15 +3896,11 @@ int lfs_deorphan(lfs_t *lfs) {
// return err; // return err;
// } // }
// } // }
} //}
memcpy(&pdir, &dir, sizeof(pdir)); 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; return 0;
} }
/* /*

23
lfs.h
View File

@@ -129,7 +129,7 @@ enum lfs_type {
// internal sources // internal sources
LFS_FROM_REGION = 0x000, LFS_FROM_REGION = 0x000,
LFS_FROM_DISK = 0x200, LFS_FROM_DISK = 0x200,
LFS_FROM_MOVE = 0x004, LFS_FROM_MOVE = 0x0ff,
}; };
// File open flags // File open flags
@@ -296,10 +296,17 @@ typedef struct lfs_mattrlist {
struct lfs_mattrlist *next; struct lfs_mattrlist *next;
} lfs_mattrlist_t; } lfs_mattrlist_t;
typedef struct lfs_entry { //typedef struct lfs_entry {
lfs_block_t pair[2]; // lfs_block_t pair[2];
uint16_t id; // uint16_t id;
} lfs_entry_t; //} 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 { typedef struct lfs_mdir {
lfs_block_t pair[2]; lfs_block_t pair[2];
@@ -310,7 +317,7 @@ typedef struct lfs_mdir {
uint16_t count; uint16_t count;
bool erased; bool erased;
bool split; bool split;
lfs_entry_t idelete; lfs_globals_t globals;
bool stop_at_commit; // TODO hmmm bool stop_at_commit; // TODO hmmm
uint16_t moveid; // TODO rm me uint16_t moveid; // TODO rm me
} lfs_mdir_t; } lfs_mdir_t;
@@ -380,8 +387,8 @@ typedef struct lfs {
lfs_free_t free; lfs_free_t free;
bool deorphaned; bool deorphaned;
lfs_entry_t idelete; lfs_globals_t globals;
lfs_entry_t diff; lfs_globals_t diff;
lfs_size_t inline_size; lfs_size_t inline_size;
lfs_size_t attrs_size; lfs_size_t attrs_size;

View File

@@ -59,7 +59,7 @@ tests/test.py << TEST
lfs_rename(&lfs, "b/hello", "c/hello") => 0; lfs_rename(&lfs, "b/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
truncate -s-7 blocks/6 truncate -s-11 blocks/6
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "b") => 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_rename(&lfs, "c/hello", "d/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST TEST
truncate -s-7 blocks/8 truncate -s-11 blocks/8
truncate -s-7 blocks/a truncate -s-11 blocks/a
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;
lfs_dir_open(&lfs, &dir[0], "c") => 0; lfs_dir_open(&lfs, &dir[0], "c") => 0;
@@ -108,6 +108,32 @@ tests/test.py << TEST
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
TEST 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 ---" echo "--- Move dir ---"
tests/test.py << TEST tests/test.py << TEST
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0;