mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 08:42:40 +01:00 
			
		
		
		
	Merge pull request #487 from littlefs-project/fix-alloc-reset-modulus
Fix several wear-leveling issues found in lfs_alloc_reset
This commit is contained in:
		
							
								
								
									
										39
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -452,14 +452,16 @@ static int lfs_alloc_lookahead(void *p, lfs_block_t block) { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // indicate allocated blocks have been committed into the filesystem, this | ||||||
|  | // is to prevent blocks from being garbage collected in the middle of a | ||||||
|  | // commit operation | ||||||
| static void lfs_alloc_ack(lfs_t *lfs) { | static void lfs_alloc_ack(lfs_t *lfs) { | ||||||
|     lfs->free.ack = lfs->cfg->block_count; |     lfs->free.ack = lfs->cfg->block_count; | ||||||
| } | } | ||||||
|  |  | ||||||
| // Invalidate the lookahead buffer. This is done during mounting and | // drop the lookahead buffer, this is done during mounting and failed | ||||||
| // failed traversals | // traversals in order to avoid invalid lookahead state | ||||||
| static void lfs_alloc_reset(lfs_t *lfs) { | static void lfs_alloc_drop(lfs_t *lfs) { | ||||||
|     lfs->free.off = lfs->seed % lfs->cfg->block_size; |  | ||||||
|     lfs->free.size = 0; |     lfs->free.size = 0; | ||||||
|     lfs->free.i = 0; |     lfs->free.i = 0; | ||||||
|     lfs_alloc_ack(lfs); |     lfs_alloc_ack(lfs); | ||||||
| @@ -505,7 +507,7 @@ static int lfs_alloc(lfs_t *lfs, lfs_block_t *block) { | |||||||
|         memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size); |         memset(lfs->free.buffer, 0, lfs->cfg->lookahead_size); | ||||||
|         int err = lfs_fs_traverseraw(lfs, lfs_alloc_lookahead, lfs, true); |         int err = lfs_fs_traverseraw(lfs, lfs_alloc_lookahead, lfs, true); | ||||||
|         if (err) { |         if (err) { | ||||||
|             lfs_alloc_reset(lfs); |             lfs_alloc_drop(lfs); | ||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -870,8 +872,10 @@ static lfs_stag_t lfs_dir_fetchmatch(lfs_t *lfs, | |||||||
|                 ptag ^= (lfs_tag_t)(lfs_tag_chunk(tag) & 1U) << 31; |                 ptag ^= (lfs_tag_t)(lfs_tag_chunk(tag) & 1U) << 31; | ||||||
|  |  | ||||||
|                 // toss our crc into the filesystem seed for |                 // toss our crc into the filesystem seed for | ||||||
|                 // pseudorandom numbers |                 // pseudorandom numbers, note we use another crc here | ||||||
|                 lfs->seed ^= crc; |                 // as a collection function because it is sufficiently | ||||||
|  |                 // random and convenient | ||||||
|  |                 lfs->seed = lfs_crc(lfs->seed, &crc, sizeof(crc)); | ||||||
|  |  | ||||||
|                 // update with what's found so far |                 // update with what's found so far | ||||||
|                 besttag = tempbesttag; |                 besttag = tempbesttag; | ||||||
| @@ -1261,12 +1265,13 @@ static int lfs_dir_commitattr(lfs_t *lfs, struct lfs_commit *commit, | |||||||
| } | } | ||||||
|  |  | ||||||
| static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { | static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { | ||||||
|     const lfs_off_t off1 = commit->off; |  | ||||||
|     const uint32_t crc1 = commit->crc; |  | ||||||
|     // align to program units |     // align to program units | ||||||
|     const lfs_off_t end = lfs_alignup(off1 + 2*sizeof(uint32_t), |     const lfs_off_t end = lfs_alignup(commit->off + 2*sizeof(uint32_t), | ||||||
|             lfs->cfg->prog_size); |             lfs->cfg->prog_size); | ||||||
|  |  | ||||||
|  |     lfs_off_t off1 = 0; | ||||||
|  |     uint32_t crc1 = 0; | ||||||
|  |  | ||||||
|     // create crc tags to fill up remainder of commit, note that |     // create crc tags to fill up remainder of commit, note that | ||||||
|     // padding is not crced, which lets fetches skip padding but |     // padding is not crced, which lets fetches skip padding but | ||||||
|     // makes committing a bit more complicated |     // makes committing a bit more complicated | ||||||
| @@ -1302,6 +1307,12 @@ static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { | |||||||
|             return err; |             return err; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         // keep track of non-padding checksum to verify | ||||||
|  |         if (off1 == 0) { | ||||||
|  |             off1 = commit->off + sizeof(uint32_t); | ||||||
|  |             crc1 = commit->crc; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         commit->off += sizeof(tag)+lfs_tag_size(tag); |         commit->off += sizeof(tag)+lfs_tag_size(tag); | ||||||
|         commit->ptag = tag ^ ((lfs_tag_t)reset << 31); |         commit->ptag = tag ^ ((lfs_tag_t)reset << 31); | ||||||
|         commit->crc = 0xffffffff; // reset crc for next "commit" |         commit->crc = 0xffffffff; // reset crc for next "commit" | ||||||
| @@ -1315,7 +1326,7 @@ static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { | |||||||
|  |  | ||||||
|     // successful commit, check checksums to make sure |     // successful commit, check checksums to make sure | ||||||
|     lfs_off_t off = commit->begin; |     lfs_off_t off = commit->begin; | ||||||
|     lfs_off_t noff = off1 + sizeof(uint32_t); |     lfs_off_t noff = off1; | ||||||
|     while (off < end) { |     while (off < end) { | ||||||
|         uint32_t crc = 0xffffffff; |         uint32_t crc = 0xffffffff; | ||||||
|         for (lfs_off_t i = off; i < noff+sizeof(uint32_t); i++) { |         for (lfs_off_t i = off; i < noff+sizeof(uint32_t); i++) { | ||||||
| @@ -3797,8 +3808,10 @@ int lfs_mount(lfs_t *lfs, const struct lfs_config *cfg) { | |||||||
|     lfs->gstate.tag += !lfs_tag_isvalid(lfs->gstate.tag); |     lfs->gstate.tag += !lfs_tag_isvalid(lfs->gstate.tag); | ||||||
|     lfs->gdisk = lfs->gstate; |     lfs->gdisk = lfs->gstate; | ||||||
|  |  | ||||||
|     // setup free lookahead |     // setup free lookahead, to distribute allocations uniformly across | ||||||
|     lfs_alloc_reset(lfs); |     // boots, we start the allocator at a random location | ||||||
|  |     lfs->free.off = lfs->seed % lfs->cfg->block_count; | ||||||
|  |     lfs_alloc_drop(lfs); | ||||||
|  |  | ||||||
|     LFS_TRACE("lfs_mount -> %d", 0); |     LFS_TRACE("lfs_mount -> %d", 0); | ||||||
|     return 0; |     return 0; | ||||||
|   | |||||||
| @@ -106,7 +106,7 @@ def main(args): | |||||||
|             struct.unpack('<HH', superblock[1].data[0:4].ljust(4, b'\xff')))) |             struct.unpack('<HH', superblock[1].data[0:4].ljust(4, b'\xff')))) | ||||||
|     print("%-47s%s" % ("littlefs v%s.%s" % version, |     print("%-47s%s" % ("littlefs v%s.%s" % version, | ||||||
|         "data (truncated, if it fits)" |         "data (truncated, if it fits)" | ||||||
|         if not any([args.no_truncate, args.tags, args.log, args.all]) else "")) |         if not any([args.no_truncate, args.log, args.all]) else "")) | ||||||
|  |  | ||||||
|     # print gstate |     # print gstate | ||||||
|     print("gstate 0x%s" % ''.join('%02x' % c for c in gstate)) |     print("gstate 0x%s" % ''.join('%02x' % c for c in gstate)) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user