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