mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 08:42:40 +01:00 
			
		
		
		
	WIP added deorphan bit to globals
This commit is contained in:
		
							
								
								
									
										365
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										365
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -267,7 +267,7 @@ 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); | ||||
| int lfs_forceconsistency(lfs_t *lfs); | ||||
|  | ||||
|  | ||||
| /// Block allocator /// | ||||
| @@ -456,15 +456,68 @@ static inline lfs_size_t lfs_tagsize(uint32_t tag) { | ||||
|     return tag & 0x00000fff; | ||||
| } | ||||
|  | ||||
| // operations on globals | ||||
| static void lfs_globalsxor(lfs_globals_t *a, const lfs_globals_t *b) { | ||||
|     a->move.pair[0] ^= b->move.pair[0]; | ||||
|     a->move.pair[1] ^= b->move.pair[1]; | ||||
|     a->move.id      ^= b->move.id; | ||||
| // operations on set of globals | ||||
| static inline void lfs_globalxor(lfs_global_t *a, const lfs_global_t *b) { | ||||
|     for (int i = 0; i < sizeof(lfs_global_t)/2; i++) { | ||||
|         a->u16[i] ^= b->u16[i]; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static bool lfs_globalsiszero(const lfs_globals_t *a) { | ||||
|     return (a->move.pair[0] == 0 && a->move.pair[1] == 0 && a->move.id == 0); | ||||
| static inline bool lfs_globaliszero(const lfs_global_t *a) { | ||||
|     for (int i = 0; i < sizeof(lfs_global_t)/2; i++) { | ||||
|         if (a->u16[i] != 0) { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| static inline void lfs_globalzero(lfs_global_t *a) { | ||||
|     memset(a->u16, 0x00, sizeof(lfs_global_t)); | ||||
| } | ||||
|  | ||||
| static inline void lfs_globalones(lfs_global_t *a) { | ||||
|     memset(a->u16, 0xff, sizeof(lfs_global_t)); | ||||
| } | ||||
|  | ||||
| static inline void lfs_globalxormove(lfs_global_t *a, | ||||
|         const lfs_block_t pair[2], uint16_t id) { | ||||
|     a->u16[0] ^= id; | ||||
|     for (int i = 0; i < sizeof(lfs_block_t[2])/2; i++) { | ||||
|         a->u16[1+i] ^= ((uint16_t*)pair)[i]; | ||||
|     } | ||||
| } | ||||
|  | ||||
| static inline void lfs_globalxordeorphaned(lfs_global_t *a, bool deorphaned) { | ||||
|     a->u16[0] ^= deorphaned << 15; | ||||
| } | ||||
|  | ||||
| static inline const lfs_block_t *lfs_globalmovepair(const lfs_t *lfs) { | ||||
|     return (const lfs_block_t*)&lfs->globals.u16[1]; | ||||
| } | ||||
|  | ||||
| static inline uint16_t lfs_globalmoveid(const lfs_t *lfs) { | ||||
|     return 0x3ff & lfs->globals.u16[0]; | ||||
| } | ||||
|  | ||||
| static inline bool lfs_globalisdeorphaned(const lfs_t *lfs) { | ||||
|     return 0x8000 & lfs->globals.u16[0]; | ||||
| } | ||||
|  | ||||
| static inline void lfs_globalmove(lfs_t *lfs, | ||||
|         const lfs_block_t pair[2], uint16_t id) { | ||||
|     lfs_global_t diff; | ||||
|     lfs_globalzero(&diff); | ||||
|     lfs_globalxormove(&diff, lfs_globalmovepair(lfs), lfs_globalmoveid(lfs)); | ||||
|     lfs_globalxormove(&diff, pair, id); | ||||
|     lfs_globalxor(&lfs->locals, &diff); | ||||
|     lfs_globalxor(&lfs->globals, &diff); | ||||
| } | ||||
|  | ||||
| static inline void lfs_globaldeorphaned(lfs_t *lfs, bool deorphaned) { | ||||
|     deorphaned ^= lfs_globalisdeorphaned(lfs); | ||||
|     lfs_globalxordeorphaned(&lfs->locals, deorphaned); | ||||
|     lfs_globalxordeorphaned(&lfs->globals, deorphaned); | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -670,15 +723,15 @@ static int lfs_commitmove(lfs_t *lfs, struct lfs_commit *commit, | ||||
| } | ||||
|  | ||||
| static int lfs_commitglobals(lfs_t *lfs, struct lfs_commit *commit, | ||||
|         lfs_globals_t *locals) { | ||||
|     if (lfs_globalsiszero(&lfs->diff)) { | ||||
|         lfs_global_t *locals) { | ||||
|     if (lfs_globaliszero(&lfs->locals)) { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     lfs_globalsxor(locals, &lfs->diff); | ||||
|     lfs_globalxor(locals, &lfs->locals); | ||||
|     int err = lfs_commitattr(lfs, commit, | ||||
|             LFS_MKTAG(LFS_TYPE_GLOBALS, 0x3ff, sizeof(*locals)), locals); | ||||
|     lfs_globalsxor(locals, &lfs->diff); | ||||
|             LFS_MKTAG(LFS_TYPE_GLOBALS, 0x3ff, sizeof(lfs_global_t)), locals); | ||||
|     lfs_globalxor(locals, &lfs->locals); | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| @@ -759,7 +812,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->locals = (lfs_globals_t){{{0}}}; | ||||
|     lfs_globalzero(&dir->locals); | ||||
|  | ||||
|     // don't write out yet, let caller take care of that | ||||
|     return 0; | ||||
| @@ -774,8 +827,8 @@ static int lfs_dir_compact(lfs_t *lfs, | ||||
|  | ||||
|     // There's nothing special about our global delta, so feed it back | ||||
|     // into the global global delta | ||||
|     lfs_globalsxor(&lfs->diff, &dir->locals); | ||||
|     dir->locals = (lfs_globals_t){{{0}}}; | ||||
|     lfs_globalxor(&lfs->locals, &dir->locals); | ||||
|     lfs_globalzero(&dir->locals); | ||||
|  | ||||
|     // increment revision count | ||||
|     dir->rev += 1; | ||||
| @@ -933,8 +986,8 @@ relocate: | ||||
|  | ||||
|     if (!relocated) { | ||||
|         // successful commit, update globals | ||||
|         lfs_globalsxor(&dir->locals, &lfs->diff); | ||||
|         lfs->diff = (lfs_globals_t){{{0}}}; | ||||
|         lfs_globalxor(&dir->locals, &lfs->locals); | ||||
|         lfs_globalzero(&lfs->locals); | ||||
|     } else { | ||||
|         // update references if we relocated | ||||
|         LFS_DEBUG("Relocating %d %d to %d %d", | ||||
| @@ -962,18 +1015,21 @@ relocate: | ||||
|  | ||||
| static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, | ||||
|         const lfs_mattr_t *attrs) { | ||||
|     bool canceling = (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0); | ||||
|     lfs_mattr_t cancel; | ||||
|     if (canceling) { | ||||
|     lfs_mattr_t cancelattr; | ||||
|     lfs_global_t canceldiff; | ||||
|     lfs_globalzero(&canceldiff); | ||||
|     if (lfs_paircmp(dir->pair, lfs_globalmovepair(lfs)) == 0) { | ||||
|         // Wait, we have the move? Just cancel this out here | ||||
|         // We need to, or else the move can become outdated | ||||
|         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; | ||||
|         lfs_globalxormove(&canceldiff, | ||||
|                 lfs_globalmovepair(lfs), lfs_globalmoveid(lfs)); | ||||
|         lfs_globalxormove(&canceldiff,  | ||||
|                 (lfs_block_t[2]){0xffffffff, 0xffffffff}, 0x3ff); | ||||
|         lfs_globalxor(&lfs->locals, &canceldiff); | ||||
|  | ||||
|         cancel.tag = LFS_MKTAG(LFS_TYPE_DELETE, lfs->globals.move.id, 0); | ||||
|         cancel.next = attrs; | ||||
|         attrs = &cancel; | ||||
|         cancelattr.tag = LFS_MKTAG(LFS_TYPE_DELETE, lfs_globalmoveid(lfs), 0); | ||||
|         cancelattr.next = attrs; | ||||
|         attrs = &cancelattr; | ||||
|     } | ||||
|  | ||||
|     // calculate new directory size | ||||
| @@ -1001,7 +1057,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, | ||||
|                     pdir.split = dir->split; | ||||
|                     pdir.tail[0] = dir->tail[0]; | ||||
|                     pdir.tail[1] = dir->tail[1]; | ||||
|                     lfs_globalsxor(&lfs->diff, &dir->locals); | ||||
|                     lfs_globalxor(&lfs->locals, &dir->locals); | ||||
|                     return lfs_dir_commit(lfs, &pdir, | ||||
|                             LFS_MKATTR(LFS_TYPE_TAIL + pdir.split, 0x3ff, | ||||
|                                 pdir.tail, sizeof(pdir.tail), | ||||
| @@ -1074,16 +1130,12 @@ compact: | ||||
|         dir->off = commit.off; | ||||
|         dir->etag = commit.ptag; | ||||
|         // successful commit, update globals | ||||
|         lfs_globalsxor(&dir->locals, &lfs->diff); | ||||
|         lfs->diff = (lfs_globals_t){{{0}}}; | ||||
|         lfs_globalxor(&dir->locals, &lfs->locals); | ||||
|         lfs_globalzero(&lfs->locals); | ||||
|     } | ||||
|  | ||||
|     // update globals that are affected | ||||
|     if (canceling) { | ||||
|         lfs->globals.move.pair[0] = 0xffffffff; | ||||
|         lfs->globals.move.pair[1] = 0xffffffff; | ||||
|         lfs->globals.move.id = 0x3ff; | ||||
|     } | ||||
|     lfs_globalxor(&lfs->globals, &canceldiff); | ||||
|  | ||||
|     // update any directories that are affected | ||||
|     for (lfs_dir_t *d = lfs->dirs; d; d = d->next) { | ||||
| @@ -1147,7 +1199,8 @@ static int32_t lfs_dir_find(lfs_t *lfs, | ||||
|         uint16_t tempcount = 0; | ||||
|         lfs_block_t temptail[2] = {0xffffffff, 0xffffffff}; | ||||
|         bool tempsplit = false; | ||||
|         lfs_globals_t templocals = (lfs_globals_t){{{0}}}; | ||||
|         lfs_global_t templocals; | ||||
|         lfs_globalzero(&templocals); | ||||
|  | ||||
|         while (true) { | ||||
|             // extract next tag | ||||
| @@ -1252,11 +1305,11 @@ static int32_t lfs_dir_find(lfs_t *lfs, | ||||
|         // consider what we have good enough | ||||
|         if (dir->off > 0) { | ||||
|             // synthetic move | ||||
|             if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0) { | ||||
|                 if (lfs->globals.move.id == lfs_tagid(foundtag)) { | ||||
|             if (lfs_paircmp(dir->pair, lfs_globalmovepair(lfs)) == 0) { | ||||
|                 if (lfs_globalmoveid(lfs) == lfs_tagid(foundtag)) { | ||||
|                     foundtag = LFS_ERR_NOENT; | ||||
|                 } else if (lfs_tagisvalid(foundtag) && | ||||
|                         lfs->globals.move.id < lfs_tagid(foundtag)) { | ||||
|                         lfs_globalmoveid(lfs) < lfs_tagid(foundtag)) { | ||||
|                     foundtag -= LFS_MKTAG(0, 1, 0); | ||||
|                 } | ||||
|             } | ||||
| @@ -1286,8 +1339,8 @@ static int lfs_dir_fetch(lfs_t *lfs, | ||||
| static int32_t lfs_dir_get(lfs_t *lfs, lfs_mdir_t *dir, | ||||
|         uint32_t getmask, uint32_t gettag, void *buffer) { | ||||
|     int32_t getdiff = 0; | ||||
|     if (lfs_paircmp(dir->pair, lfs->globals.move.pair) == 0 && | ||||
|             lfs_tagid(gettag) <= lfs->globals.move.id) { | ||||
|     if (lfs_paircmp(dir->pair, lfs_globalmovepair(lfs)) == 0 && | ||||
|             lfs_tagid(gettag) <= lfs_globalmoveid(lfs)) { | ||||
|         // synthetic moves | ||||
|         getdiff = LFS_MKTAG(0, 1, 0); | ||||
|     } | ||||
| @@ -1422,11 +1475,9 @@ static int lfs_dir_getinfo(lfs_t *lfs, lfs_mdir_t *dir, | ||||
| /// Top level directory operations /// | ||||
| int lfs_mkdir(lfs_t *lfs, const char *path) { | ||||
|     // deorphan if we haven't yet, needed at most once after poweron | ||||
|     if (!lfs->deorphaned) { | ||||
|         int err = lfs_deorphan(lfs); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
|     int err = lfs_forceconsistency(lfs); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     lfs_mdir_t cwd; | ||||
| @@ -1445,7 +1496,7 @@ int lfs_mkdir(lfs_t *lfs, const char *path) { | ||||
|     lfs_alloc_ack(lfs); | ||||
|  | ||||
|     lfs_mdir_t dir; | ||||
|     int err = lfs_dir_alloc(lfs, &dir, false, cwd.tail); | ||||
|     err = lfs_dir_alloc(lfs, &dir, false, cwd.tail); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
| @@ -1817,8 +1868,8 @@ int lfs_file_opencfg(lfs_t *lfs, lfs_file_t *file, | ||||
|         const char *path, int flags, | ||||
|         const struct lfs_file_config *cfg) { | ||||
|     // deorphan if we haven't yet, needed at most once after poweron | ||||
|     if ((flags & 3) != LFS_O_RDONLY && !lfs->deorphaned) { | ||||
|         int err = lfs_deorphan(lfs); | ||||
|     if ((flags & 3) != LFS_O_RDONLY) { | ||||
|         int err = lfs_forceconsistency(lfs); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
| @@ -2543,15 +2594,13 @@ int lfs_stat(lfs_t *lfs, const char *path, struct lfs_info *info) { | ||||
|  | ||||
| int lfs_remove(lfs_t *lfs, const char *path) { | ||||
|     // deorphan if we haven't yet, needed at most once after poweron | ||||
|     if (!lfs->deorphaned) { | ||||
|         int err = lfs_deorphan(lfs); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
|     int err = lfs_forceconsistency(lfs); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     lfs_mdir_t cwd; | ||||
|     int err = lfs_dir_fetch(lfs, &cwd, lfs->root); | ||||
|     err = lfs_dir_fetch(lfs, &cwd, lfs->root); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
| @@ -2580,6 +2629,9 @@ int lfs_remove(lfs_t *lfs, const char *path) { | ||||
|         if (dir.count > 0 || dir.split) { | ||||
|             return LFS_ERR_NOTEMPTY; | ||||
|         } | ||||
|  | ||||
|         // mark fs as orphaned | ||||
|         lfs_globaldeorphaned(lfs, false); | ||||
|     } | ||||
|  | ||||
|     // delete the entry | ||||
| @@ -2596,11 +2648,14 @@ int lfs_remove(lfs_t *lfs, const char *path) { | ||||
|             return err; | ||||
|         } | ||||
|  | ||||
|         // fix orphan | ||||
|         lfs_globaldeorphaned(lfs, true); | ||||
|  | ||||
|         // steal state | ||||
|         // TODO test for global state stealing? | ||||
|         cwd.tail[0] = dir.tail[0]; | ||||
|         cwd.tail[1] = dir.tail[1]; | ||||
|         lfs_globalsxor(&lfs->diff, &dir.locals); | ||||
|         lfs_globalxor(&lfs->locals, &dir.locals); | ||||
|         err = lfs_dir_commit(lfs, &cwd, | ||||
|                 LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff, | ||||
|                     cwd.tail, sizeof(cwd.tail), | ||||
| @@ -2615,11 +2670,9 @@ int lfs_remove(lfs_t *lfs, const char *path) { | ||||
|  | ||||
| int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | ||||
|     // deorphan if we haven't yet, needed at most once after poweron | ||||
|     if (!lfs->deorphaned) { | ||||
|         int err = lfs_deorphan(lfs); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
|     int err = lfs_forceconsistency(lfs); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     // find old entry | ||||
| @@ -2665,6 +2718,9 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | ||||
|             if (prevdir.count > 0 || prevdir.split) { | ||||
|                 return LFS_ERR_NOTEMPTY; | ||||
|             } | ||||
|  | ||||
|             // mark fs as orphaned | ||||
|             lfs_globaldeorphaned(lfs, false); | ||||
|         } | ||||
|     } else { | ||||
|         // check that name fits | ||||
| @@ -2678,15 +2734,10 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | ||||
|     } | ||||
|  | ||||
|     // 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      = lfs_tagid(oldtag) ^ lfs->globals.move.id; | ||||
|     lfs->globals.move.pair[0] = oldcwd.pair[0]; | ||||
|     lfs->globals.move.pair[1] = oldcwd.pair[1]; | ||||
|     lfs->globals.move.id      = lfs_tagid(oldtag); | ||||
|     lfs_globalmove(lfs, oldcwd.pair, lfs_tagid(oldtag)); | ||||
|  | ||||
|     // move over all attributes | ||||
|     int err = lfs_dir_commit(lfs, &newcwd, | ||||
|     err = lfs_dir_commit(lfs, &newcwd, | ||||
|             LFS_MKATTR(lfs_tagtype(oldtag), newid, newpath, strlen(newpath), | ||||
|             LFS_MKATTR(LFS_FROM_MOVE, newid, &oldcwd, lfs_tagid(oldtag), | ||||
|             NULL))); | ||||
| @@ -2709,11 +2760,14 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | ||||
|             return err; | ||||
|         } | ||||
|  | ||||
|         // fix orphan | ||||
|         lfs_globaldeorphaned(lfs, true); | ||||
|  | ||||
|         // steal state | ||||
|         // TODO test for global state stealing? | ||||
|         newcwd.tail[0] = prevdir.tail[0]; | ||||
|         newcwd.tail[1] = prevdir.tail[1]; | ||||
|         lfs_globalsxor(&lfs->diff, &prevdir.locals); | ||||
|         lfs_globalxor(&lfs->locals, &prevdir.locals); | ||||
|         err = lfs_dir_commit(lfs, &newcwd, | ||||
|                 LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff, | ||||
|                     newcwd.tail, sizeof(newcwd.tail), | ||||
| @@ -2743,7 +2797,7 @@ int lfs_rename(lfs_t *lfs, const char *oldpath, const char *newpath) { | ||||
| //    // if we were a directory, find pred, replace tail | ||||
| //    // TODO can this just deorphan? | ||||
| //    if (prevexists && lfs_tagsubtype(prevattr.tag) == LFS_TYPE_DIR) { | ||||
| //        err = lfs_deorphan(lfs); | ||||
| //        err = lfs_forceconsistency(lfs); | ||||
| //        if (err) { | ||||
| //            return err; | ||||
| //        } | ||||
| @@ -2936,10 +2990,7 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) { | ||||
|     lfs->root[1] = 0xffffffff; | ||||
|     lfs->files = NULL; | ||||
|     lfs->dirs = NULL; | ||||
|     lfs->deorphaned = false; | ||||
|     lfs->globals.move.pair[0] = 0xffffffff; | ||||
|     lfs->globals.move.pair[1] = 0xffffffff; | ||||
|     lfs->globals.move.id      = 0x3ff; | ||||
|     lfs_globalones(&lfs->globals); | ||||
|  | ||||
|     // scan for any global updates | ||||
|     // TODO rm me? need to grab any inits | ||||
| @@ -3348,7 +3399,7 @@ static int lfs_relocate(lfs_t *lfs, | ||||
|         } | ||||
|  | ||||
|         // clean up bad block, which should now be a desync | ||||
|         return lfs_deorphan(lfs); | ||||
|         return lfs_forceconsistency(lfs); | ||||
|     } | ||||
|  | ||||
|     // find pred | ||||
| @@ -3380,7 +3431,7 @@ int lfs_scan(lfs_t *lfs) { | ||||
|     } | ||||
|  | ||||
|     lfs_mdir_t dir = {.tail = {0, 1}}; | ||||
|     lfs->diff = (lfs_globals_t){{{0}}}; | ||||
|     lfs_globalzero(&lfs->locals); | ||||
|  | ||||
|     // iterate over all directory directory entries | ||||
|     while (!lfs_pairisnull(dir.tail)) { | ||||
| @@ -3390,40 +3441,105 @@ int lfs_scan(lfs_t *lfs) { | ||||
|         } | ||||
|  | ||||
|         // xor together indirect deletes | ||||
|         lfs_globalsxor(&lfs->diff, &dir.locals); | ||||
|         lfs_globalxor(&lfs->locals, &dir.locals); | ||||
|     } | ||||
|  | ||||
|     // update littlefs with globals | ||||
|     // TODO does this only run once? | ||||
|     // TODO Should we inline this into init?? | ||||
|     lfs_globalsxor(&lfs->globals, &lfs->diff); | ||||
|     lfs->diff = (lfs_globals_t){{{0}}}; | ||||
|     if (!lfs_pairisnull(lfs->globals.move.pair)) { | ||||
|     lfs_globalxor(&lfs->globals, &lfs->locals); | ||||
|     lfs_globalzero(&lfs->locals); | ||||
|     if (!lfs_pairisnull(lfs_globalmovepair(lfs))) { | ||||
|         LFS_DEBUG("Found move %d %d %d", | ||||
|                 lfs->globals.move.pair[0], | ||||
|                 lfs->globals.move.pair[1], | ||||
|                 lfs->globals.move.id); | ||||
|                 lfs_globalmovepair(lfs)[0], | ||||
|                 lfs_globalmovepair(lfs)[1], | ||||
|                 lfs_globalmoveid(lfs)); | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int lfs_deorphan(lfs_t *lfs) { | ||||
|     lfs->deorphaned = true; | ||||
|     if (lfs_pairisnull(lfs->root)) { // TODO rm me? | ||||
|         return 0; | ||||
| int lfs_forceconsistency(lfs_t *lfs) { | ||||
|     if (!lfs_globalisdeorphaned(lfs)) { | ||||
|         // Fix any orphans | ||||
|         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) { | ||||
|                 // check if we have a parent | ||||
|                 lfs_mdir_t parent; | ||||
|                 int32_t tag = lfs_parent(lfs, pdir.tail, &parent); | ||||
|                 if (tag < 0 && tag != LFS_ERR_NOENT) { | ||||
|                     return tag; | ||||
|                 } | ||||
|  | ||||
|                 if (tag == LFS_ERR_NOENT) { | ||||
|                     // we are an orphan | ||||
|                     LFS_DEBUG("Found orphan %d %d", | ||||
|                             pdir.tail[0], pdir.tail[1]); | ||||
|  | ||||
|                     pdir.tail[0] = dir.tail[0]; | ||||
|                     pdir.tail[1] = dir.tail[1]; | ||||
|                     err = lfs_dir_commit(lfs, &pdir, | ||||
|                             LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff, | ||||
|                                 pdir.tail, sizeof(pdir.tail), | ||||
|                             NULL)); | ||||
|                     if (err) { | ||||
|                         return err; | ||||
|                     } | ||||
|  | ||||
|                     break; | ||||
|                 } | ||||
|  | ||||
|                 lfs_block_t pair[2]; | ||||
|                 int32_t res = lfs_dir_get(lfs, &parent, 0x7ffff000, tag, pair); | ||||
|                 if (res < 0) { | ||||
|                     return res; | ||||
|                 } | ||||
|  | ||||
|                 if (!lfs_pairsync(pair, pdir.tail)) { | ||||
|                     // we have desynced | ||||
|                     LFS_DEBUG("Found half-orphan %d %d", pair[0], pair[1]); | ||||
|  | ||||
|                     pdir.tail[0] = pair[0]; | ||||
|                     pdir.tail[1] = pair[1]; | ||||
|                     err = lfs_dir_commit(lfs, &pdir, | ||||
|                             LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff, | ||||
|                                 pdir.tail, sizeof(pdir.tail), | ||||
|                             NULL)); | ||||
|                     if (err) { | ||||
|                         return err; | ||||
|                     } | ||||
|  | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             memcpy(&pdir, &dir, sizeof(pdir)); | ||||
|         } | ||||
|  | ||||
|         // mark orphan as fixed | ||||
|         lfs_globaldeorphaned(lfs, false); | ||||
|     } | ||||
|  | ||||
|     // Fix bad moves | ||||
|     if (!lfs_pairisnull(lfs->globals.move.pair)) { | ||||
|     if (lfs_globalmoveid(lfs) != 0x3ff) { | ||||
|         // Fix bad moves | ||||
|         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); | ||||
|                 lfs_globalmovepair(lfs)[0], | ||||
|                 lfs_globalmovepair(lfs)[1], | ||||
|                 lfs_globalmoveid(lfs)); | ||||
|  | ||||
|         // fetch and delete the moved entry | ||||
|         lfs_mdir_t movedir; | ||||
|         int err = lfs_dir_fetch(lfs, &movedir, lfs->globals.move.pair); | ||||
|         int err = lfs_dir_fetch(lfs, &movedir, lfs_globalmovepair(lfs)); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
| @@ -3435,69 +3551,6 @@ int lfs_deorphan(lfs_t *lfs) { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     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) { | ||||
|             // check if we have a parent | ||||
|             lfs_mdir_t parent; | ||||
|             int32_t tag = lfs_parent(lfs, pdir.tail, &parent); | ||||
|             if (tag < 0 && tag != LFS_ERR_NOENT) { | ||||
|                 return tag; | ||||
|             } | ||||
|  | ||||
|             if (tag == LFS_ERR_NOENT) { | ||||
|                 // we are an orphan | ||||
|                 LFS_DEBUG("Found orphan %d %d", pdir.tail[0], pdir.tail[1]); | ||||
|  | ||||
|                 pdir.tail[0] = dir.tail[0]; | ||||
|                 pdir.tail[1] = dir.tail[1]; | ||||
|                 err = lfs_dir_commit(lfs, &pdir, | ||||
|                         LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff, | ||||
|                             pdir.tail, sizeof(pdir.tail), | ||||
|                         NULL)); | ||||
|                 if (err) { | ||||
|                     return err; | ||||
|                 } | ||||
|  | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             lfs_block_t pair[2]; | ||||
|             int32_t res = lfs_dir_get(lfs, &parent, 0x7ffff000, tag, pair); | ||||
|             if (res < 0) { | ||||
|                 return res; | ||||
|             } | ||||
|  | ||||
|             if (!lfs_pairsync(pair, pdir.tail)) { | ||||
|                 // we have desynced | ||||
|                 LFS_DEBUG("Found half-orphan %d %d", pair[0], pair[1]); | ||||
|  | ||||
|                 pdir.tail[0] = pair[0]; | ||||
|                 pdir.tail[1] = pair[1]; | ||||
|                 err = lfs_dir_commit(lfs, &pdir, | ||||
|                         LFS_MKATTR(LFS_TYPE_SOFTTAIL, 0x3ff, | ||||
|                             pdir.tail, sizeof(pdir.tail), | ||||
|                         NULL)); | ||||
|                 if (err) { | ||||
|                     return err; | ||||
|                 } | ||||
|  | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         memcpy(&pdir, &dir, sizeof(pdir)); | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										29
									
								
								lfs.h
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								lfs.h
									
									
									
									
									
								
							| @@ -110,7 +110,7 @@ enum lfs_type { | ||||
|     LFS_TYPE_TAIL           = 0x0c0, | ||||
|     LFS_TYPE_SOFTTAIL       = 0x0c0, | ||||
|     LFS_TYPE_HARDTAIL       = 0x0c1, | ||||
|     LFS_TYPE_CRC            = 0x0ff, | ||||
|     LFS_TYPE_CRC            = 0x0ff, // TODO are trailing ones useful? | ||||
|  | ||||
|     LFS_TYPE_INLINESTRUCT   = 0x040, | ||||
|     LFS_TYPE_CTZSTRUCT      = 0x041, | ||||
| @@ -280,12 +280,9 @@ typedef struct lfs_mattr { | ||||
|     const struct lfs_mattr *next; | ||||
| } lfs_mattr_t; | ||||
|  | ||||
| typedef struct lfs_globals { | ||||
|     struct lfs_move { | ||||
|         lfs_block_t pair[2]; | ||||
|         uint16_t id; | ||||
|     } move; | ||||
| } lfs_globals_t; | ||||
| typedef union lfs_global { | ||||
|     uint16_t u16[5]; | ||||
| } lfs_global_t; | ||||
|  | ||||
| typedef struct lfs_mdir { | ||||
|     lfs_block_t pair[2]; | ||||
| @@ -296,7 +293,7 @@ typedef struct lfs_mdir { | ||||
|     uint16_t count; | ||||
|     bool erased; | ||||
|     bool split; | ||||
|     lfs_globals_t locals; | ||||
|     lfs_global_t locals; | ||||
| } lfs_mdir_t; | ||||
|  | ||||
| typedef struct lfs_cache { | ||||
| @@ -314,12 +311,13 @@ typedef struct lfs_file { | ||||
|         lfs_size_t size; | ||||
|     } ctz; | ||||
|  | ||||
|     const struct lfs_file_config *cfg; | ||||
|     uint32_t flags; | ||||
|     lfs_off_t pos; | ||||
|     lfs_block_t block; | ||||
|     lfs_off_t off; | ||||
|     lfs_cache_t cache; | ||||
|  | ||||
|     const struct lfs_file_config *cfg; | ||||
| } lfs_file_t; | ||||
|  | ||||
| typedef struct lfs_dir { | ||||
| @@ -353,21 +351,18 @@ typedef struct lfs_free { | ||||
|  | ||||
| // The littlefs type | ||||
| typedef struct lfs { | ||||
|     const struct lfs_config *cfg; | ||||
|     lfs_cache_t rcache; | ||||
|     lfs_cache_t pcache; | ||||
|  | ||||
|     lfs_block_t root[2]; | ||||
|     lfs_file_t *files; | ||||
|     lfs_dir_t *dirs; | ||||
|  | ||||
|     lfs_cache_t rcache; | ||||
|     lfs_cache_t pcache; | ||||
|  | ||||
|     lfs_global_t globals; | ||||
|     lfs_global_t locals; | ||||
|     lfs_free_t free; | ||||
|     bool deorphaned; | ||||
|     lfs_globals_t globals2; | ||||
|     lfs_globals_t globals; | ||||
|     lfs_globals_t diff; | ||||
|  | ||||
|     const struct lfs_config *cfg; | ||||
|     lfs_size_t inline_size; | ||||
|     lfs_size_t attr_size; | ||||
|     lfs_size_t name_size; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user