mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 00:32:38 +01:00 
			
		
		
		
	Merge pull request #242 from ARMmbed/fix-2048-erase-size
Fix issues with large prog sizes (prog_size > 1KiB)
This commit is contained in:
		
							
								
								
									
										111
									
								
								lfs.c
									
									
									
									
									
								
							
							
						
						
									
										111
									
								
								lfs.c
									
									
									
									
									
								
							| @@ -1227,65 +1227,85 @@ static int lfs_dir_commitattr(lfs_t *lfs, struct lfs_commit *commit, | ||||
|  | ||||
| static int lfs_dir_commitcrc(lfs_t *lfs, struct lfs_commit *commit) { | ||||
|     // align to program units | ||||
|     lfs_off_t off = lfs_alignup(commit->off + 2*sizeof(uint32_t), | ||||
|     const lfs_off_t off1 = commit->off + sizeof(lfs_tag_t); | ||||
|     const lfs_off_t end = lfs_alignup(off1 + sizeof(uint32_t), | ||||
|             lfs->cfg->prog_size); | ||||
|  | ||||
|     // read erased state from next program unit | ||||
|     lfs_tag_t tag; | ||||
|     int err = lfs_bd_read(lfs, | ||||
|             NULL, &lfs->rcache, sizeof(tag), | ||||
|             commit->block, off, &tag, sizeof(tag)); | ||||
|     if (err && err != LFS_ERR_CORRUPT) { | ||||
|         return err; | ||||
|     } | ||||
|     // create crc tags to fill up remainder of commit, note that | ||||
|     // padding is not crcd, which lets fetches skip padding but | ||||
|     // makes committing a bit more complicated | ||||
|     while (commit->off < end) { | ||||
|         lfs_off_t off = commit->off + sizeof(lfs_tag_t); | ||||
|         lfs_off_t noff = lfs_min(end - off, 0x3fe) + off; | ||||
|         if (noff < end) { | ||||
|             noff = lfs_min(noff, end - 2*sizeof(uint32_t)); | ||||
|         } | ||||
|  | ||||
|     // build crc tag | ||||
|     bool reset = ~lfs_frombe32(tag) >> 31; | ||||
|     tag = LFS_MKTAG(LFS_TYPE_CRC + reset, 0x3ff, | ||||
|         off - (commit->off+sizeof(lfs_tag_t))); | ||||
|         // read erased state from next program unit | ||||
|         lfs_tag_t tag = 0xffffffff; | ||||
|         int err = lfs_bd_read(lfs, | ||||
|                 NULL, &lfs->rcache, sizeof(tag), | ||||
|                 commit->block, noff, &tag, sizeof(tag)); | ||||
|         if (err && err != LFS_ERR_CORRUPT) { | ||||
|             return err; | ||||
|         } | ||||
|  | ||||
|     // write out crc | ||||
|     uint32_t footer[2]; | ||||
|     footer[0] = lfs_tobe32(tag ^ commit->ptag); | ||||
|     commit->crc = lfs_crc(commit->crc, &footer[0], sizeof(footer[0])); | ||||
|     footer[1] = lfs_tole32(commit->crc); | ||||
|     err = lfs_bd_prog(lfs, | ||||
|             &lfs->pcache, &lfs->rcache, false, | ||||
|             commit->block, commit->off, &footer, sizeof(footer)); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
|     commit->off += sizeof(tag)+lfs_tag_size(tag); | ||||
|     commit->ptag = tag ^ (reset << 31); | ||||
|         // build crc tag | ||||
|         bool reset = ~lfs_frombe32(tag) >> 31; | ||||
|         tag = LFS_MKTAG(LFS_TYPE_CRC + reset, 0x3ff, noff - off); | ||||
|  | ||||
|     // flush buffers | ||||
|     err = lfs_bd_sync(lfs, &lfs->pcache, &lfs->rcache, false); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     // successful commit, check checksum to make sure | ||||
|     uint32_t crc = 0xffffffff; | ||||
|     lfs_size_t size = commit->off - lfs_tag_size(tag) - commit->begin; | ||||
|     for (lfs_off_t i = 0; i < size; i++) { | ||||
|         // leave it up to caching to make this efficient | ||||
|         uint8_t dat; | ||||
|         err = lfs_bd_read(lfs, | ||||
|                 NULL, &lfs->rcache, size-i, | ||||
|                 commit->block, commit->begin+i, &dat, 1); | ||||
|         // write out crc | ||||
|         uint32_t footer[2]; | ||||
|         footer[0] = lfs_tobe32(tag ^ commit->ptag); | ||||
|         commit->crc = lfs_crc(commit->crc, &footer[0], sizeof(footer[0])); | ||||
|         footer[1] = lfs_tole32(commit->crc); | ||||
|         err = lfs_bd_prog(lfs, | ||||
|                 &lfs->pcache, &lfs->rcache, false, | ||||
|                 commit->block, commit->off, &footer, sizeof(footer)); | ||||
|         if (err) { | ||||
|             return err; | ||||
|         } | ||||
|  | ||||
|         crc = lfs_crc(crc, &dat, 1); | ||||
|         commit->off += sizeof(tag)+lfs_tag_size(tag); | ||||
|         commit->ptag = tag ^ (reset << 31); | ||||
|         commit->crc = 0xffffffff; // reset crc for next "commit" | ||||
|     } | ||||
|  | ||||
|     // flush buffers | ||||
|     int err = lfs_bd_sync(lfs, &lfs->pcache, &lfs->rcache, false); | ||||
|     if (err) { | ||||
|         return err; | ||||
|     } | ||||
|  | ||||
|     if (crc != commit->crc) { | ||||
|         return LFS_ERR_CORRUPT; | ||||
|     // successful commit, check checksums to make sure | ||||
|     lfs_off_t off = commit->begin; | ||||
|     lfs_off_t noff = off1; | ||||
|     while (off < end) { | ||||
|         uint32_t crc = 0xffffffff; | ||||
|         for (lfs_off_t i = off; i < noff+sizeof(uint32_t); i++) { | ||||
|             // leave it up to caching to make this efficient | ||||
|             uint8_t dat; | ||||
|             err = lfs_bd_read(lfs, | ||||
|                     NULL, &lfs->rcache, noff+sizeof(uint32_t)-i, | ||||
|                     commit->block, i, &dat, 1); | ||||
|             if (err) { | ||||
|                 return err; | ||||
|             } | ||||
|  | ||||
|             crc = lfs_crc(crc, &dat, 1); | ||||
|         } | ||||
|  | ||||
|         // detected write error? | ||||
|         if (crc != 0) { | ||||
|             return LFS_ERR_CORRUPT; | ||||
|         } | ||||
|  | ||||
|         // skip padding | ||||
|         off = lfs_min(end - noff, 0x3fe) + noff; | ||||
|         if (off < end) { | ||||
|             off = lfs_min(off, end - 2*sizeof(uint32_t)); | ||||
|         } | ||||
|         noff = off + sizeof(uint32_t); | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| @@ -1578,11 +1598,11 @@ static int lfs_dir_compact(lfs_t *lfs, | ||||
|             } | ||||
|  | ||||
|             // successful compaction, swap dir pair to indicate most recent | ||||
|             LFS_ASSERT(commit.off % lfs->cfg->prog_size == 0); | ||||
|             lfs_pair_swap(dir->pair); | ||||
|             dir->count = end - begin; | ||||
|             dir->off = commit.off; | ||||
|             dir->etag = commit.ptag; | ||||
|             dir->erased = (dir->off % lfs->cfg->prog_size == 0); | ||||
|             // note we able to have already handled move here | ||||
|             if (lfs_gstate_hasmovehere(&lfs->gpending, dir->pair)) { | ||||
|                 lfs_gstate_xormove(&lfs->gpending, | ||||
| @@ -1749,6 +1769,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_mdir_t *dir, | ||||
|         } | ||||
|  | ||||
|         // successful commit, update dir | ||||
|         LFS_ASSERT(commit.off % lfs->cfg->prog_size == 0); | ||||
|         dir->off = commit.off; | ||||
|         dir->etag = commit.ptag; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user